869 - DistributeUnions
Opened this issue · 0 comments
koSakano commented
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void
? I
: never;
type UnionToTuple<T> = UnionToIntersection<T extends any ? (t: T) => T : never> extends (
_: any,
) => infer W
? [...UnionToTuple<Exclude<T, W>>, W]
: [];
type Tuple = readonly unknown[];
type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
type ToString<T extends number> = `${T}`;
type StringDigit = ToString<Digit>;
type StringNumber = `${StringDigit}${string}`;
/**
* IsTuple<0[]> = false.
* IsTuple<[0]> = true.
*/
type IsTuple<T> = T extends Tuple ? (number extends T['length'] ? false : true) : false;
/**
* SetValue<[1, 2, 3], '1', 4 | 5> = [1, 4, 3] | [1, 5, 3].
* SetValue<{ foo: 2 }, 'bar', 4 | 5> = { foo: 2, bar: 4} | { foo: 2, bar : 5 }.
*/
type SetValue<T, Key extends string, Value> = Value extends unknown
? IsTuple<T> extends true
? {
[K in keyof T]: K extends Key ? Value : T[K];
}
: {
[K in Key | keyof T]: K extends Key ? Value : K extends keyof T ? T[K] : never;
}
: never;
/**
* Tail<[1, 2, 3]> = [2, 3].
*/
type Tail<T extends Tuple> = T extends readonly [unknown, ...infer Rest] ? Rest : [];
/**
* KeysUnion<{ foo: 1, bar: 2 }> = "foo" | "bar".
* KeysUnion<[3, 4, 5]>; = "0" | "1" | "2".
*/
type KeysUnion<T> = IsTuple<T> extends true ? StringNumber & keyof T : string & keyof T;
/**
* Keys<[1 | 2]> = ["0"].
*/
type Keys<T, K = UnionToTuple<KeysUnion<T>>> = K extends ReadonlyArray<KeysUnion<T>> ? K : never;
type Reduce<T, K extends ReadonlyArray<string & keyof T>> = T extends unknown
? K extends []
? T
: Reduce<SetValue<T, K[0], DistributeUnions<T[K[0]]>>, Tail<K>>
: never;
type DistributeUnions<T> = T extends object ? Reduce<T, Keys<T>> : T;