Last active
June 1, 2021 11:57
-
-
Save miyaokamarina/175d95893f000e67f98807397014fe03 to your computer and use it in GitHub Desktop.
Infers the type of object spread operation; like { ...a, ...b }, but for types.
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
declare type Refine<from, to> = from extends to ? from : never; | |
declare type ArraySize<t> = Refine<GetProperty<t, 'length'>, number>; | |
declare type GetProperty<t, k> = t[Refine<k, keyof t>]; | |
declare type ArrayType<t> = t extends ReadonlyArray<infer u> ? u : never; | |
declare type ArrayHead<a> = a extends readonly [infer h] ? h : never; | |
declare type Rebuild<t> = { [k in keyof t]: t[k] }; | |
declare type KeyofReq<o, k extends keyof o = keyof o> = k extends any ? (undefined extends o[k] ? never : k) : never; | |
// Binary spread | |
declare type ObjectSpread< | |
a, | |
b, | |
ka extends keyof a = Exclude<keyof a, keyof b>, | |
kb extends keyof b = KeyofReq<b> | Exclude<keyof b, keyof a>, | |
kc extends keyof a = Refine<Exclude<keyof a | keyof b, kb | ka>, keyof a>, | |
pa = Pick<a, ka>, | |
pb = Pick<b, kb>, | |
pc = { [l in kc]: a[l] | (l extends keyof b ? Exclude<b[l], undefined> : never) }, | |
> = Rebuild<pa & pb & pc>; | |
// Variadic spread | |
declare type ObjectAssign<t> = number extends ArraySize<t> | |
? ArrayType<t> | |
: t extends readonly [infer a, infer b, ...infer c] | |
? ObjectAssign<[ObjectSpread<a, b>, ...c]> | |
: ArrayHead<t>; | |
type xxxxxxx = ObjectAssign<[A, B, C]>; | |
interface A { | |
a1: 'A::a1', | |
b1: 'A::b1', | |
c1?: 'A::c1', | |
d1?: 'A::d1', | |
a2: 'A::a2', | |
b2: 'A::b2', | |
// c2: 'A::c2', | |
// d2: 'A::d2', | |
} | |
interface B { | |
a1: 'B::a1', | |
b1?: 'B::b1', | |
c1: 'B::c1', | |
d1?: 'B::d1', | |
a2: 'B::a2', | |
// b2: 'B::b2', | |
c2: 'B::c2', | |
// d2: 'B::d2', | |
readonly a3?: 'B::a3', | |
readonly b3?: 'B::b3', | |
} | |
interface C { | |
readonly a3: 'C::a3', | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment