-
-
Notifications
You must be signed in to change notification settings - Fork 11
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
fix: Pick and Omit over intersection types #31
Conversation
Codecov Report
@@ Coverage Diff @@
## master #31 +/- ##
=====================================
Coverage 100% 100%
=====================================
Files 15 15
Lines 70 70
Branches 3 3
=====================================
Hits 70 70
Continue to review full report at Codecov.
|
🎉 This PR is included in version 1.21.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
@unional I am concerned about compiler performance, distributive conditional types tend to cause performance issues with large unions. But other than that it should be fine if What do you mean Thanks for the attribution :) |
Thanks. I'm debating whether should the user concern with compiler performance when they choose which type to use. IMO it should be about behavior. Should the user need to know about the gritty detail? It doesn't work on intersection with generics. You can check it out here |
Performance isn't an issue until it is. But I agree functionality is more important. The reason it does not work on intersection with generics is that conditional types with unresolved type parameters are not expanded, so `UnionKeys<T & Foo> is opaque to the compiler inside the generic function. One change that can improve this situation is to add type UnionKeys<T> = keyof T | (T extends any ? keyof T : never) |
Thanks, that works! 🌷 Agree with what you said. If we have a way to distinguish between normal unions and discriminative unions, we can fall back to the more performant way, but forcing user to use a different On a side note, what do you think about: type UnionKeys<T> = keyof T | (T extends any ? keyof T : never)
// vs
type UnionKeys<T> = keyof T | (T extends T ? keyof T : never) |
I used to use |
Got it. Based on this example, it seems like |
Yeah, if it's not type UnionKeys<T> = keyof T | (T extends T ? keyof T : never)
type Pick2<T, K extends UnionKeys<T>> = T extends T ? Pick<T, K> : never
type Pick3<T, K extends keyof T> = T extends T ? { [P in K]: T[P] } : never
type Foo = { a: string, b: string }
type Boo = { a?: string, b: string }
function foo<T>(i2: Pick2<Foo & T, 'a'>, i3: Pick3<Foo & T, 'a'>): void {
}
let x: Pick2<Foo | Boo, 'a'> // Pick<Foo, "a"> | Pick<Boo, "a">
let y: Pick3<Foo | Boo, 'a'> // { a: string } | { a?: string | undefined } |
Yes, but that is just trying to push it down to get the type works again with For this usage, what is the benefit of using I can't find an example that using |
@unional (Sorry saw the comment forgot to respond). I can't think of any concrete use cases where I would want to type UnionKeys<T> = keyof T | (T extends T ? keyof T : never)
type Id<T> = {} & { [ P in keyof T]: T[P]} // just for esthetics
type Pick2<T, K extends UnionKeys<T>> = T extends T ? Pick<T, Extract<K, keyof T>> : never
type Union = {
type: "A",
foo: string
} | {
type: "B",
foo: string
bar: string
}
type PickedUnion = Id<Pick2<Union, "type" | "bar">>
//same as
type PickedUnionResult = {
type: "A";
} | {
type: "B";
bar: string;
} I think for |
Thanks! That's a great example. Thanks for all your input and your continuous contribution to SO and to the community. 🌷 |
@dragomirtitian
I get the initial implementation of these
Pick<>
andOmit<>
from your comment microsoft/TypeScript#28339 (comment)I tried it out and found that the
UnionKeys<>
does not work on intersection types.Do you see any concern of using
keyof T
overUnionKeys<>
?