TypeScript 里的 Tuple 魔法
1
2
3
4
5
type X = Multiply<2, 5>;
// type X = 10;

type A = Sort<[3, 5, 1, 2, 4]>;
// type A = [1, 2, 3, 4, 5];

Type instantiation is excessively deep and possibly infinite.

好烦,不想写了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// ============================== BASE ==============================

type E = unknown;

type Num = E[];

type Zero = [];

type Next<X extends Num> = [E, ...X];
type Prev<X extends Num> = X extends [E, ...infer R] ? R : never;

type One = Next<Zero>; // [E]

type _1 = Prev<Next<One>>; // [E]

// ============================== CONVERSION ==============================

type ToLit<X extends Num> = X["length"];

type FromLit<N extends number, R extends Num = Zero> =
R["length"] extends N ? R :
FromLit<N, Next<R>>;

type _2 = ToLit<[E, E]>; // 2
type _3 = FromLit<3>; // [E, E, E]

// ============================== BASIC OPS ==============================

type Add<X extends Num, Y extends Num> = [...X, ...Y];
type Sub<X extends Num, Y extends Num> = X extends [...Y, ...infer R] ? R : never;

type _4 = ToLit<Add<FromLit<3>, FromLit<1>>>; // 4
type _5 = ToLit<Sub<FromLit<7>, FromLit<2>>>; // 5

type Eq<X extends Num, Y extends Num> = X extends Y ? true : false;
type Neq<X extends Num, Y extends Num> = X extends Y ? false : true;
type Less<X extends Num, Y extends Num> = X extends [...Y, ...Num] ? false : true;
type Geq<X extends Num, Y extends Num> = X extends [...Y, ...Num] ? true : false;
type Gtr<X extends Num, Y extends Num> = Y extends [...X, ...Num] ? false : true;
type Leq<X extends Num, Y extends Num> = Y extends [...X, ...Num] ? true : false;

type _6 = Eq<FromLit<6>, FromLit<6>>; // true
type _7 = Eq<FromLit<6>, FromLit<7>>; // false

type _8 = Less<FromLit<8>, FromLit<9>>; // true
type _9 = Less<FromLit<9>, FromLit<9>>; // false

// ============================== RECURSIVE OPS ==============================

type Mul<X extends Num, Y extends Num, R extends Num = Zero> =
Y extends Zero ? R :
Mul<X, Prev<Y>, Add<R, X>>;

type _10 = ToLit<Mul<FromLit<2>, FromLit<5>>>; // 10

type Div<X extends Num, Y extends Num, R extends Num = Zero> =
Less<X, Y> extends true ? R :
Div<Sub<X, Y>, Y, Next<R>>;

type Mod<X extends Num, Y extends Num> =
Less<X, Y> extends true ? X :
Mod<Sub<X, Y>, Y>;

type _11 = ToLit<Div<FromLit<11>, FromLit<5>>>; // 2
type _12 = ToLit<Mod<FromLit<11>, FromLit<5>>>; // 1

type Pow<X extends Num, Y extends Num> =
X extends Zero ? Zero :
_Pow<X, Y, One>;

type _Pow<X extends Num, Y extends Num, R extends Num> =
Y extends Zero ? R :
_Pow<X, Prev<Y>, Mul<R, X>>;

type _13 = ToLit<Pow<FromLit<2>, FromLit<13>>>; // 8192

type Fact<X extends Num, R extends Num = One> =
X extends Zero ? R :
Fact<Prev<X>, Mul<R, X>>;

type _14 = ToLit<Fact<FromLit<7>>>; // 5040

type IsPrime<X extends Num> =
X extends Zero ? false :
X extends One ? false :
_IsPrime<X, Next<One>>;

type _IsPrime<X extends Num, I extends Num> =
Less<X, Mul<I, I>> extends true ? true :
Mod<X, I> extends Zero ? false :
_IsPrime<X, Next<I>>;

type _15 = IsPrime<FromLit<13>>; // true
type _16 = IsPrime<FromLit<16>>; // false

// ============================== ARRAY ==============================

type Rest<A extends any[]> =
A extends [any, ...infer R] ? R : [];

type _17 = Rest<["a", "b", "c"]>; // ["b", "c"]

type FromLitArr<A extends number[]> =
A extends [] ? [] :
[FromLit<A[0]>, ...FromLitArr<Rest<A>>];

type ToLitArr<A extends Num[]> =
A extends [] ? [] :
[ToLit<A[0]>, ...ToLitArr<Rest<A>>];

type _18 = FromLitArr<[3, 6]>; /* [ [E, E, E],
[E, E, E, E, E, E] ] */

type _19 = ToLitArr<_18>; // [3, 6]

type Factor<X extends Num, I extends Num = Next<One>, R extends Num[] = []> =
X extends One ?
R :
Less<X, Mul<I, I>> extends true ?
[...R, X] :
Mod<X, I> extends Zero ?
Factor<Div<X, I>, Next<One>, [...R, I]> :
Factor<X, Next<I>, R>;

type _20 = ToLitArr<Factor<FromLit<20>>>; // [2, 2, 5]

type Insert<A extends Num[], X extends Num, R extends Num[] = []> =
A extends [] ? [...R, X] :
Less<X, A[0]> extends true ?
[...R, X, ...A] :
Insert<Rest<A>, X, [...R, A[0]]>;

type _21 = ToLitArr<Insert<FromLitArr<[1, 3, 4]>, FromLit<2>>>; // [1, 2, 3, 4]

type Sort<A extends Num[]> =
A extends [] ? [] :
A extends [Num] ? A :
Insert<Sort<Rest<A>>, A[0]>;

type _22 = ToLitArr<Sort<FromLitArr<[3, 5, 1, 2, 4]>>>; // [1, 2, 3, 4, 5]

// ============================== OTHERS ==============================

type Mapper<T, R extends any[] = []> =
R["length"] extends keyof T ?
Mapper<T, [...R, T[R["length"]]]> :
R;

type Original = { 0: number, 1: string, 2: boolean };
type Mapped = Mapper<Original>; // [number, string, boolean];
Author: Piggy
Link: https://blog.piggy.moe/post/ts-tuple-magic/
Copyright Notice: All articles in this blog are licensed under CC BY-NC 4.0 unless stating additionally.