TypeScript 类型系统不是图灵完备,没有数值相关逻辑。对于数值相关的逻辑比较绕。需要数组长度做计数。
TypeScript 类型系统中没有加减乘除运算符,但是可以通过构造不同的数组然后取 length 的方式来完成数值计算,把数值的加减乘除转化为对数组的提取和构造。
数组长度实现加减乘除
type BuildArray<
Length extends number,
Ele = unknown,
Arr extends unknown[] = []
> = Arr['length'] extends Length
? Arr
: BuildArray<Length, Ele, [...Arr, Ele]>;
// Add
// 通过 BuildArray 构造两个数组,然后合并成一个,取 length
type Add<Num1 extends number, Num2 extends number> =
[...BuildArray<Num1>, ...BuildArray<Num2>]['length'];
// Subtract
type Subtract<Num1 extends number, Num2 extends number> =
BuildArray<Num1> extends [...arr1: BuildArray<Num2>, ...arr2: infer Rest]
? Rest['length']
: never;
// Multiply Times
// 乘法是多个加法结果的累加,类型参数 ResultArr 保存中间结果,默认值 [],相当于从 0 开始加。
// 每加一次就把 Num2 减 1,直到 Num2 为 0,就代表加完
type Multip<
Num1 extends number,
Num2 extends number,
ResultArr extends unknown[] = []
> = Num2 extends 0 ? ResultArr['length']
: Multiply<Num1, Substract<Num2, 1>, [...BuildArray<Num1>, ...ResultArr]>;
// Divide
// 除法的实现就是被减数不断减去减数,直到减为 0,记录减了几次就是结果
type Divide<
Num1 extends number,
Num2 extends number,
CountArr extends unknown[] = []
> = Num1 extends 0 ? CountArr['length']
: Divide<Subtract<Num1, Num2>, Num2, [unknown, ...CountArr]>;
数组长度实现计数
StrLen
数组长度可以取 length 来得到,但字符串类型不能取 length,所以要实现一个求字符串长度的高级类型。
// StrLen
// 每次取一个并计数,直到取完,就是字符串的长度
type StrLen<
Str extends string,
CountArr extends unknown[] = []
> = Str extends `${string}${infer Rest}`
? StrLen<Rest, [...CountArr, unknown]>
: CountArr['length'];
GreaterThan
// GreaterThan
type GreaterThan<
Num1 extends number,
Num2 extends number,
CountArr extends unknown[] = []
> = Num1 extends Num2
? false
: CountArr['length'] extends Num2
? true
: CountArr['length'] extends Num1
? false
: GreaterThan<Num1, Num2, [...CountArr, unknown]>;
Fibonacci
// Fibonacci
type FibonacciLoop<
PrevArr extends unknown[],
CurrentArr extends unknown[],
IndexArr extends unknown[] = [],
Number extends number = 1
> = IndexArr['length'] extends Num
? CurrentArr['length']
: FibonacciLoop<CurrentArr, [...PrevArr, ...CurrentArr], [...IndexArr, unknown], Num>