Created
September 18, 2022 21:22
-
-
Save fostyfost/96a465e7ba1e8e9832284cc6ad19e79c to your computer and use it in GitHub Desktop.
Union to Intersection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @see https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type | |
// union to intersection converter by @jcalz | |
// Intersect<{ a: 1 } | { b: 2 }> = { a: 1 } & { b: 2 } | |
type Intersect<T> = (T extends any ? ((x: T) => 0) : never) extends ((x: infer R) => 0) ? R : never | |
// get keys of tuple | |
// TupleKeys<[string, string, string]> = 0 | 1 | 2 | |
type TupleKeys<T extends any[]> = Exclude<keyof T, keyof []> | |
// apply { foo: ... } to every type in tuple | |
// Foo<[1, 2]> = { 0: { foo: 1 }, 1: { foo: 2 } } | |
type Foo<T extends any[]> = { | |
[K in TupleKeys<T>]: {foo: T[K]} | |
} | |
// get union of field types of an object (another answer by @jcalz again, I guess) | |
// Values<{ a: string, b: number }> = string | number | |
type Values<T> = T[keyof T] | |
// TS won't believe the result will always have a field "foo" | |
// so we have to check for it with a conditional first | |
type Unfoo<T> = T extends { foo: any } ? T["foo"] : never | |
// combine three helpers to get an intersection of all the item types | |
type IntersectItems<T extends any[]> = Unfoo<Intersect<Values<Foo<T>>>> | |
type Test = [ | |
{ a: 1 } | { b: 2 }, | |
{ c: 3 }, | |
] | |
// this is what we wanted | |
type X = IntersectItems<Test> // { a: 1, c: 3 } | { b: 2, c: 3 } | |
// this is not what we wanted | |
type Y = Intersect<Test[number]> // { a: 1, b: 2, c: 3 } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment