TypeScript 类型系统不是图灵完备,没有数值相关逻辑。对于数值相关的逻辑比较绕。需要数组长度做计数。
TypeScript 类型系统中没有加减乘除运算符,但是可以通过构造不同的数组然后取 length 的方式来完成数值计算,把数值的加减乘除转化为对数组的提取和构造。

数组长度实现加减乘除

  1. type BuildArray<
  2. Length extends number,
  3. Ele = unknown,
  4. Arr extends unknown[] = []
  5. > = Arr['length'] extends Length
  6. ? Arr
  7. : BuildArray<Length, Ele, [...Arr, Ele]>;
  8. // Add
  9. // 通过 BuildArray 构造两个数组,然后合并成一个,取 length
  10. type Add<Num1 extends number, Num2 extends number> =
  11. [...BuildArray<Num1>, ...BuildArray<Num2>]['length'];
  12. // Subtract
  13. type Subtract<Num1 extends number, Num2 extends number> =
  14. BuildArray<Num1> extends [...arr1: BuildArray<Num2>, ...arr2: infer Rest]
  15. ? Rest['length']
  16. : never;
  17. // Multiply Times
  18. // 乘法是多个加法结果的累加,类型参数 ResultArr 保存中间结果,默认值 [],相当于从 0 开始加。
  19. // 每加一次就把 Num2 减 1,直到 Num2 为 0,就代表加完
  20. type Multip<
  21. Num1 extends number,
  22. Num2 extends number,
  23. ResultArr extends unknown[] = []
  24. > = Num2 extends 0 ? ResultArr['length']
  25. : Multiply<Num1, Substract<Num2, 1>, [...BuildArray<Num1>, ...ResultArr]>;
  26. // Divide
  27. // 除法的实现就是被减数不断减去减数,直到减为 0,记录减了几次就是结果
  28. type Divide<
  29. Num1 extends number,
  30. Num2 extends number,
  31. CountArr extends unknown[] = []
  32. > = Num1 extends 0 ? CountArr['length']
  33. : Divide<Subtract<Num1, Num2>, Num2, [unknown, ...CountArr]>;

数组长度实现计数

StrLen
数组长度可以取 length 来得到,但字符串类型不能取 length,所以要实现一个求字符串长度的高级类型。

  1. // StrLen
  2. // 每次取一个并计数,直到取完,就是字符串的长度
  3. type StrLen<
  4. Str extends string,
  5. CountArr extends unknown[] = []
  6. > = Str extends `${string}${infer Rest}`
  7. ? StrLen<Rest, [...CountArr, unknown]>
  8. : 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>