Last active
September 14, 2020 22:14
-
-
Save tokland/8750311b712f69659f1dce88e08714ee to your computer and use it in GitHub Desktop.
Flatten a union into a plain type with a union of all keys (optional for non-common keys)
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
type AllKeysOfUnion<U> = U extends any ? keyof U : never; | |
type NonCommonKeysOfUnion<U> = Exclude<AllKeysOfUnion<U>, keyof U>; | |
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>; | |
type UnionWithKeys<U, K extends keyof any> = U extends any | |
? { [Key in K]: Key extends keyof U ? U[Key] : never } | |
: never; | |
export type FlattenUnion<U> = PartialBy< | |
UnionWithKeys<U, AllKeysOfUnion<U>>, | |
NonCommonKeysOfUnion<U> | |
>; | |
// Compile-time testing helpers | |
type IsEqual<T1, T2> = [T1] extends [T2] ? ([T2] extends [T1] ? true : false) : false; | |
const assertEqualTypes = <T1, T2>(_eq: IsEqual<T1, T2>): void => {}; | |
const assertValueHasType = <T>(_value: T): void => {}; | |
// Usage example | |
type UnionType = | |
| { type: "type1"; key1: number; key2: symbol } | |
| { type: "type2"; key1: string } | |
| { type: "type3"; key2: string }; | |
type FlattenUnionType = FlattenUnion<UnionType>; | |
assertEqualTypes<keyof FlattenUnionType, "type" | "key1" | "key2">(true); | |
assertEqualTypes<FlattenUnionType["type"], "type1" | "type2" | "type3">(true); | |
assertEqualTypes<FlattenUnionType["key1"], number | string | undefined>(true); | |
assertEqualTypes<FlattenUnionType["key2"], symbol | string | undefined>(true); | |
assertValueHasType<FlattenUnionType>({ type: "type1" }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment