-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Pick doesn't preserve optional from unions #28483
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
At present this is a design limitation - mapped types only preserve the modifiers of their inputs when the input key type is (almost exactly) |
Wait, don't union types lose optional modifiers on common properties anyway? Even without mapped types, that is: type U = A | B;
declare const u : U;
u.optional // not listed as an optional property anymore |
@jcalz it looks that they don't. Given the example in Playground I linked above the following code doesn't show any type errors: let works: A | B = { other: '' }; Updated Playground Link |
Sure, but that's because checking assignability to a union type involves checking assignability to each member and finding at least one match. I'm just noting that the IntelliSense type inspection behaves differently for union types from the way it behaves for, say, intersection types: type U = A | B;
declare const u : U;
u.optional // (property) optional: string | undefined
type I = A & B;
declare const i : I;
i.optional // (property) optional?: string | undefined It looks like a property present in both {[K in keyof (X | Y)]: (X | Y)[K]} But backing up, what do you really want out of a mapped union type? For example: type M = {a: number, b: string, c: boolean};
type N = {a: string, b: number, d: boolean};
type P = Pick<M | N, 'a' | 'b'>;
const whoops: P = {a: 123, b: 456}; // no error! Do you like the current behavior of getting If you are happier with the latter, then you can get that and the optional modifiers for free by using distributive conditional types: type PickU<T, K extends keyof T> = T extends any ? {[P in K]: T[P]} : never; That behaves just like type PickUnion = PickU<A | B, 'optional'>;
let worksNow: PickUnion = {}; // no error and this: type P = PickU<M | N, 'a' | 'b'>;
const whoops: P = {a: 123, b: 456}; // error! number not assignable to string Just a thought... if you replace your usages of |
Closing the issue. |
@jcalz The Could you explain why this is working differently from type Pick<T, K extends keyof T> = { [P in K]: T[P]; }; from lib.es5.d.ts
type PickU<T, K extends keyof T> = T extends any ? {[P in K]: T[P]} : never; looks just like type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
-type PickU<T, K extends keyof T> = T extends any ? {[P in K]: T[P]} : never;
+type PickU<T, K extends keyof T> = T extends any ? Pick<T, K> : never; which should be equivalent if type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
- type PickU<T, K extends keyof T> = T extends any ? Pick<T, K> : never;
+ type PickU<T extends any, K extends keyof T> = Pick<T, K>; Why is that conditional changing the behavior of |
@eps1lon The difference is that conditional types are distributive over unions when you use a bare type parameter before |
@jcalz So |
Yes. I can't think of something that would break if the definition of |
There is an open issue about this although it doesn't have much activity: #28339 |
Uh oh!
There was an error while loading. Please reload this page.
TypeScript Version: 3.2.0-dev.20181110
Search Terms: Pick preserve optional union
Code
Expected behavior:
Pick
should preserve optional property when used on unionsActual behavior:
It doesn't
Playground Link: link
The text was updated successfully, but these errors were encountered: