Skip to content

Instantly share code, notes, and snippets.

@Ziphil
Last active April 26, 2020 19:38
Show Gist options
  • Save Ziphil/8971d4fe6f39fa3f679d36e7517c3449 to your computer and use it in GitHub Desktop.
Save Ziphil/8971d4fe6f39fa3f679d36e7517c3449 to your computer and use it in GitHub Desktop.
// T が S を継承していることを型推論器に伝えます。
// 型制約エラーを抑制するために利用できます。
type Cast<T, S> = T extends S ? T : S;
type Append<T, A extends Array<any>> = ((arg: T, ...rest: A) => void) extends ((...args: infer B) => void) ? B : never;
type Remove<A extends Array<any>> = A["length"] extends 0 ? [] : ((...args: A) => void) extends (arg: any, ...rest: infer B) => void ? B : [];
// 数値リテラル型を any から成るタプル型に変換します。
// 例えば、ToTuple<3> は [any, any, any] に評価されます。
type ToTuple<N extends number> = ToTupleRec<N, []>;
type ToTupleRec<N, A extends Array<any>> = {
0: A,
1: ToTupleRec<N, Append<any, A>>
}[A extends {length: N} ? 0 : 1];
// タプル型を数値リテラル型に変換します。
type FromTuple<A extends Array<any>> = A["length"];
// 型レベル自然数の後続数を計算します。
type Succ<N extends number> = FromTuple<Append<any, ToTuple<N> extends infer X ? Cast<X, Array<any>> : never>>;
// 2 つの型レベル自然数の和を計算します。
type Plus<M extends number, N extends number> = PlusRec<M, N, M, []>;
type PlusRec<M, N, R extends number, A extends Array<any>> = {
0: R,
1: PlusRec<M, N, Succ<R>, Append<any, A>>
}[A extends {length: N} ? 0 : 1];
type Seven = Plus<4, 3>; // 7
type Twelve = Plus<3, 9>; // 12
// 型レベル自然数の前者数を計算します。
type Prev<N extends number> = FromTuple<Remove<ToTuple<N> extends infer X ? Cast<X, Array<any>> : never>>;
// 2 つの型レベル自然数の差を計算します。
type Minus<M extends number, N extends number> = MinusRec<M, N, M, []>;
type MinusRec<M, N, R extends number, A extends Array<any>> = {
0: R,
1: MinusRec<M, N, Prev<R>, Append<any, A>>
}[A extends {length: N} ? 0 : 1];
type Six = Minus<9, 3>; // 6
// 2 つの型レベル自然数の積を計算します。
type Times<M extends number, N extends number> = TimesRec<M, N, 0, []>;
type TimesRec<M extends number, N, R extends number, A extends Array<any>> = {
0: R,
1: TimesRec<M, N, Plus<R, M> extends infer X ? Cast<X, number> : never, Append<any, A>>
}[A extends {length: N} ? 0 : 1];
type Fifteen = Times<3, 5>; // 15
type TwentyFour = Times<4, 6>; // 24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment