-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Nullable nested properties breaks inference for type guards #60244
Comments
This has little to do with type guards, or even nullability. It's just assignability. The following is an error, for good reason: declare const i: { foo: { bar: string | null } };
const j: ({ foo: { bar: string } } | { foo: null }) = i; // error! but removing declare const i: { foo: { bar: string } };
const j: ({ foo: { bar: string } } | { foo: null }) = i; // okay Those are the same types from your example, and the error in the top one is the thing that prevents TS from selecting the type guard overload for TypeScript can't know that you intend |
Hmm okay I get the question of assignability in this case, but why doesn’t the type guard error that I’m passing an argument of the wrong type to it if items can’t be coerced to NullableItem[]? |
|
IMO, the typechecker should error if the type guard can't narrow. The way type guards behave in other situations very much lean towards them being the source of truth, and the syntax implies that. The return type being |
It's not that the type guard can't narrow, it's that Maybe you're saying that the non-narrowing call signature should reject callbacks that return a type predicate, but that would make the already complicated Or maybe the narrowing call signature shouldn't care if interface Array<T> {
filter<S extends U, U extends ([T] extends [U] ? unknown : never)>(
predicate: (value: U, index: number, array: U[]) => value is S, thisArg?: any
): (S & T)[];
filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[];
} which works for your use case but again, makes the already complicated thing even more complicated. It especially hurts that you can't say I'd say there's a valid request in here about |
No I agree it's not a bug in type guards, me opening this as a bug is just my lack of knowledge, but I appreciate your explanations. Though I think at a deeper level what it boils down to that feels wrong to me (which correct me if I'm wrong is why the filter overload I was expecting can't be chosen) is—to use another simpler example—that this: type NullableItem = {
foo: string | null;
};
type NotNullableItem = {
foo: string;
};
const itemHasFoo = (item: NullableItem): item is NotNullableItem => {
return item.foo !== null;
};
const myThing = { foo: null };
if (itemHasFoo(myThing)) {
console.log(myThing.foo);
} Leads to |
This would just make it inconsistent with narrowing semantics. It's idiomatic and common for something to be reduced to |
This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
🔎 Search Terms
nullable items nested typeguard type guards
🕗 Version & Regression Information
⏯ Playground Link
https://www.typescriptlang.org/play/?ts=5.7.0-dev.20241016#code/ATAuE8AcFNgMQPYIEIEMBOwC8wDeAoEEAIwwC5gBnUdASwDsBzYAH2HoFcAbLgbkOABffgIgxgAOW5dUxLtACSoaAFtseASABmSCohQZW7afxDD8oqLAkJQUnrPlLV6gkWA6EepGnSmhIiAAxgj01MC0yioAEqiU+uoAFJGqFPYycopRAJQUKWq0lJK26Y5ZLlgAfBru6NCgHOj0EVEAdJ7AAIRYOJw8-uYCIWGgLapFOADamjXuHrqzc8Ck6BQA5AAW0DwIawA0M2YH7oLHRLjzXsY8QmcAuoHAw+FcCIwAgujoqOAA8lrOFQTYCJLQcehBQGUNIlaRlQGTO7ZbDVNxEZ4IeStV6MUHgyFRSjZAaPZ6jLS0LjKOoAEyh6nylHalOpySisXiSGJAhxn2+fwBhNBLOgtKhxKAA
💻 Code
🙁 Actual behavior
Type guard itemHasFoo does not narrow type to NotNullableItem, but when
FooBar
is changed to:It works fine, something about the nullable property of FooBar seems to stop the inference of that type correctly.
🙂 Expected behavior
I expect the typeguard to correctly narrow the type to
NotNullableItem
and therefore not error.Additional information about the issue
No response
The text was updated successfully, but these errors were encountered: