Skip to content

Instantly share code, notes, and snippets.

@miyaokamarina
Last active June 1, 2021 11:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miyaokamarina/175d95893f000e67f98807397014fe03 to your computer and use it in GitHub Desktop.
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.
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