Last active
March 8, 2019 10:08
-
-
Save hasparus/72d9ff63dc8f5dd958a39f1614b31b56 to your computer and use it in GitHub Desktop.
TypeScript Playground -- Merging types
This file contains hidden or 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
// Paste this to typescriptlang.org/play or click the link the comments | |
type Expected = { | |
a: 1 | 2 | |
b?: 1 | 2 | |
c?: 1 | |
d?: 1 | 2 | |
e: 2 | |
f?: 2 | |
} | |
type TXY = { | |
a: 1 | |
b: 1 | |
c?: 1 | |
d?: 1 | |
e?: 1 | |
}; | |
type TXX = { | |
a: 2 | |
b?: 2 | |
d?: 2 | |
e: 2 | |
f: 2 | |
}; | |
type IntegerKeys<T extends Array<any>> = Exclude<keyof T, keyof typeof Array.prototype>; | |
// Step by step | |
type Arg = [TXY, TXX]; | |
type AllKeys = keyof UnionToIntersection<Arg[number]>; | |
type WithUndefined = { | |
[I in IntegerKeys<Arg>]: { [P in AllKeys]: P extends keyof Arg[I] ? Arg[I][P] : undefined } | |
} | |
type X = Simplify<WithUndefined[keyof WithUndefined]>; | |
// The Simplify up here is not mandatory, added for better tooltip | |
// Merged types in Arg | |
type Result = Simplify<{ [P in OptionalKeys<X>]?: X[P] } & { [P in RequiredKeys<X>]: X[P] }> | |
assertType<IsExtends<Expected, Result>>(); | |
assertType<IsExtends<Result, Expected>>(); // Dunno why, it looks the same to me | |
const xs: Result[] = [ | |
{ a: 2 }, { b: 1, a: 2, f: undefined }, { f: 2, a: 2 }, | |
] | |
type PickKeys<T extends object, TValue> = Exclude< | |
{ [K in keyof T]: TValue extends T[K] ? K : never }[keyof T], undefined | |
>; | |
type NullableKeys<T extends object> = PickKeys<T, null> | |
type OptionalKeys<T extends object> = PickKeys<T, undefined> | |
type RequiredKeys<T extends object> = Exclude<keyof T, OptionalKeys<T>> | |
type Simplify<T> = Pick<T, keyof T> | |
// from typical-ts | |
type UnionToIntersection<U> = ( | |
U extends any ? (k: U) => void : never | |
) extends ((k: infer I) => void) ? I : never; | |
// from typepark | |
type And<A extends boolean, B extends boolean> = A extends true ? (B extends true ? true : false) : false; | |
type Or<A extends boolean, B extends boolean> = A extends true ? true : (B extends true ? true : false); | |
type Xor<A extends boolean, B extends boolean> = A extends true ? (B extends true ? false : true) : (B extends true ? true : false); | |
type Not<X extends boolean> = X extends true ? false : true; | |
type IsExtends<A, B> = A extends B ? true : false; | |
type TypeEqNotUnion<A, B> = And<IsExtends<A, B>, IsExtends<B, A>>; | |
type ComparableType<T> = [T]; | |
type TypeEqNotAny<A, B> = TypeEqNotUnion<ComparableType<A>, ComparableType<B>>; | |
type IsAny<T> = And<TypeEqNotAny<T, 1>, TypeEqNotAny<T, 2>>; | |
type IsNotAny<T> = Not<IsAny<T>>; | |
type TypeEq<A, B> = Or<And<IsAny<A>, IsAny<B>>, And<And<IsNotAny<A>, IsNotAny<B>>, TypeEqNotAny<A, B>>>; | |
function assertType<_T extends true>() { } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Playground