-
Notifications
You must be signed in to change notification settings - Fork 12.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Predicate value is object
doesn't work in Array.prototype.filter()
#44777
Comments
Ah! I understand now. The difference is that I think I have a solution, though: this alternate definition of interface Array<T> {
filter2<S>(
callbackfn: (value: T | S, index: number, array: (T | S)[]) => value is S,
thisArg?: any
): (T & S)[];
} The biggest downside I see at the moment is that the elements come out typed as Would a PR with this as the new definition for |
Your analysis is correct, and that definition for |
I've had the same problem with when filtering unknown[] with type guards, which current ts just ignores. Building on Peeja's solution, I arrived at a solution that also addresses an edge case that broke code reliant on inferred context, changing the filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): T[] …into two overrides that both produce // make array.filter(isFoo).filter(isBar) produce Array<Foo & Bar>:
interface ReadonlyArray<T> {
filter<S extends T>(predicate: (value: T, index: number, array: readonly T[]) => value is S, thisArg?: any): (T & S)[];
filter<S>(predicate: (value: T | S, index: number, array: readonly (T | S)[]) => value is S, thisArg?: any): (T & S)[];
}
interface Array<T> {
filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): (T & S)[];
filter<S>(predicate: (value: T | S, index: number, array: (T | S)[]) => value is S, thisArg?: any): (T & S)[];
} Updated version of the PR's example, re-calibrated for current typescript 5.2.2, and with another test case that broke with Peeja's first pitch: playgrounds In other words: this problem can be addressed by this change, plus whatever test suite updates are needed. |
Bug Report
🔎 Search Terms
type narrowing, type predicate,
value is object
,filter()
,lodash.isObject
🕗 Version & Regression Information
⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
allObjects
was typed as(string | number | { a: number })[]
, so both lines belowconst allObjects
fail.🙂 Expected behavior
allObjects
should be typed as{ a: number }[]
, soallObjects[0].a
should pass the type checker. Notably, as seen above,isObject
does manage to narrow the type of a single value with the union type to the only member of the union that's an object, it just can't narrow all of the elements using.filter()
the wayisNumber
is able to.I can't conceive of why they behave differently, but I also don't know the internals well. I think this difference is undesired, but I might be missing something deeper.
The text was updated successfully, but these errors were encountered: