-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Can't exclude undefined from indexed Partial with simple guard #31908
Comments
EDIT: Nope, sorry. Misread the example. I'm guessing that maybe the narrowing code doesn't do the same level of probing to the expression type compared to when types are related. Is this a perf thing or just a missing feature? |
That's right, it's not that TypeScript doesn't narrow the type of the expression |
TypeScript doesn't know that Anyway with all that said, having the only inference position for type NotUndefined<T> = T extends undefined ? never: T;
function getValue<T, K extends keyof T>(partial: T, key: K): NotUndefined<T[K]> | null {
const value = partial[key]
if (value !== undefined) {
return value as NotUndefined<T[K]>;
}
return null
} |
I might have a similar issue: type MyEvents = 'start' | 'stop' | 'suspend';
type EventCounts = { [key in MyEvents]?: number};
const eventCounts: EventCounts = { start: 0 };
function foo<T extends MyEvents>(event: T) {
// not working - undefined is not assignable to number
const count: number = eventCounts[event] || 0;
// working
const foo: number | undefined = eventCounts[event];
const count2: number = foo || 0;
// other workarounds
const count3: number = (eventCounts[event] || 0)!;
const count4: number = eventCounts[event] as number | undefined || 0;
} I didn't really understand the reasoning about
In my case this is more direct (optional index signature). Does this hit the same design limitation? (I know that in this example the generic is only constructed, i could just use "event: MyEvents" non generic, that's also working, but not the point :)). |
In the following example, it seems like the compiler does know that type Dict<K extends string> = { [key in K]?: number }
function getValue<K extends string>(dict: Dict<K>, key: K): number {
const value = dict[key] // value: Dict<K>[K]
if (value) { // or: if (value !== undefined)
// Error: Type 'number | undefined' is not assignable to type 'number'.
return value
}
throw new Error()
} @RyanCavanaugh Thanks for the input. PR #22348 does seem related, and in particular issue #22137 that it aims to fix. The function in my example is artificial, like the function in this example; it's a reduced case, not necessarily a good helper function I would write. So my understanding is there is one solution, which is scary, which is to make type guards basically introduce an What about making it so that indexing a mapped type checks if you are indexing with the key type, or something assignable to the key type, something like that? Something like this must be happening for non-generics, because indexing a |
@dgreensp function getValue<T, K extends keyof T>(partial: Partial<T>, key: K): T[K] | null {
const value = partial[key]
if (value !== undefined) {
return value // error: TypeScript thinks this can be undefined...
}
return null
} Basically the type of @RyanCavanaugh type Partial<T> = {
[P in keyof T]?: T[P];
} What if focus is not on general type narrowing, but only related to |
I have an issue which probably has the same cause:
When compiled with
|
@stepancheg Your type in |
@MartinJohns then I don't understand how So my problem can be written like this then:
Thank you! And sorry for distraction. |
TypeScript Version: 3.5.1
Search Terms:
Indexed, Partial, undefined, guard
Code
Expected behavior:
Inside the if statement,
value
should have typeT[K]
. Especially sincepartial[key]
is assignable toT[K] | undefined
, and in fact TypeScript reports the type in the error message asT[K] | undefined
, inside the if statement! It's like it just doesn't simplifyPartial<T>[K]
until it tries returning it.Here is the workaround, which doesn't involve any casting, just hints:
It would be nice if this hint wasn't necessary.
Actual behavior:
TypeScript complains that
T[K] | undefined
is not ok to return, even though the type should beT[K]
.Playground Link:
(requires strictNullChecks)
https://www.typescriptlang.org/play/#src=function%20getValue%3CT%2C%20K%20extends%20keyof%20T%3E(partial%3A%20Partial%3CT%3E%2C%20key%3A%20K)%3A%20T%5BK%5D%20%7C%20null%20%7B%0D%0A%20%20const%20value%20%3D%20partial%5Bkey%5D%0D%0A%20%20if%20(value%20!%3D%3D%20undefined)%20%7B%0D%0A%20%20%20%20return%20value%20%2F%2F%20error%3A%20TypeScript%20thinks%20this%20can%20be%20undefined...%0D%0A%20%20%7D%0D%0A%20%20return%20null%0D%0A%7D
Related Issues:
The text was updated successfully, but these errors were encountered: