-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Wrong type inferred for nested union #20280
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
Comments
To add a bit, the motivation is providing a type-safe wrapper around // current way to do it to get type inference
const a = get(someObj, 'a');
const b = get(a, 'b');
// desired API
const b = safeGet(someObj, 'a', 'b'); |
@dwickern @chriskrycho I wrote a version using conditional types that works: type Unwrap<T> = T extends Wrapped<infer U> ? U : T;
// working example
interface Wrapped<T> {
value: T
}
type Props1<T> = {
[K in keyof T]: T[K];
}
declare function get1<T, K1 extends keyof T>(obj: Props1<T>, k1: K1): Unwrap<T[K1]>;
declare const obj1: { a: string };
const v1: string = get1(obj1, 'a'); // works
declare const obj2: { a: Wrapped<string> };
const v2: string = get1(obj2, 'a'); // works
type Props2<T> = {
[K in keyof T]: Unwrap<Props1<T[K]>>
};
declare function get2<T, K1 extends keyof T, K2 extends keyof Unwrap<T[K1]>>(obj: Props2<T>, k1: K1, k2: K2): Unwrap<Unwrap<T[K1]>[K2]>;
declare const obj3: { a: { b: string } };
const v3: string = get2(obj3, 'a', 'b'); // works
declare const obj4: { a: Wrapped<{ b: Wrapped<string> }> };
const v4: string = get2(obj4, 'a', 'b'); // now works I don't think this is solvable otherwise because we don't preferentially go down one path or the other when inferring a key type for the union. |
Ah, this is genuinely great. Thank you, @RyanCavanaugh. I don’t have time to experiment tonight; it looks like it should be possible to extend this using overloads but probably not tuple/argument types, if I’m tracking correctly? At a minimum, it’ll give us a tool we can build on for this. Thanks for circling back around to it! |
This is possible now with conditional types 🎉 |
TypeScript Version: 2.7.0-dev.20171126
Context: a method for ember.js which extracts the value from some path, e.g.
Each value in the path might be some plain object
T
or aWrapped<T>
(in which case we return the underlyingT
)Code
Typescript can infer the returned type using a union:
However, it no longer works when the union types are nested:
If I eliminate the right side of the union from
Props2
, then theobj4
example worksThe
obj4
example should pick the left side of the union to begin withThe text was updated successfully, but these errors were encountered: