TS类型挑战(2) 实现 Repeat<T, C>

244 阅读1分钟

1. 实现Repeat<T, C>用例及说明

type A = Repeat<number, 3> // [number, number, number]
type B = Repeat<string, 2> // [string, string]
type C = Repeat<1, 1> // [1, 1]
type D = Repeat<0, 0> // []

2.伪代码及自主实现Repeat<T, C>

伪代码version0.1

type Repeat<T, C extends number,B extends []> = C >= 1 ? Repeat<T, C-1, [T, ...B]> : B;

伪代码version0.2

type Repeat<T, C extends number, B extends any[] = []> = C extends 0 
? B : Repeat<T, C extends 1 ? 0 : C - 1, [T, ...B]>;

问题 c-1是直接在类型中执行算术运算,需要写辅助递减计数器实现

解决及全部代码

type Decrement<T extends number> = T extends T ? (T extends 0 ? never : T extends 1 ? 0 : T extends 2 ? 1 : T extends 3 ? 2 : T extends 4 ? 3 : T extends 5 ? 4 : T extends 6 ? 5 : T extends 7 ? 6 : T extends 8 ? 7 : T extends 9 ? 8 : number) : never;

type Repeat<T, C extends number, B extends any[] = []> = C extends 0 
? B : Repeat<T, Decrement<C>, [T, ...B]>;

Tips:

  1. 如果C是比较大的数字,可能会出现错误,因为TS对递归深度有限制
  2. Decrement写法笨

上述代码的解释:

  1. B extends any[] = []:将B设置为默认值[],在初始调用时不需要提供B
  2. C extends 0 ? B:如果计数C等于0,则返回累积数组B
  3. Repeat<T, Decrement<C>, [T, ...B]>:否则,进行递归调用,将T添加到累积数组B中。

3. 参考社区优秀代码

type Repeat<T, C extends number, R extends any[] = []> = R['length'] extends C 
? R : Repeat<T, C ,[...R, T]>
  1. Repeat<T, C extends number, R extends any[] = []>:定义了一个名为Repeat的泛型类型,它接受三个类型参数,分别为元素类型T、重复次数C和累积元组RR的默认值为[]
  2. R['length'] extends C:检查累积元组R的长度是否等于重复次数C。如果等于,则表示已经达到重复次数,应该返回累积元组R
  3. Repeat<T, C ,[...R, T]>:如果累积元组R的长度小于C,则进行递归调用。在这个递归调用中,将元素类型T添加到累积元组R的末尾。