TS类型挑战(3)实现 Filter<T, A>

85 阅读2分钟

1. case说明及解释


type A = Filter<[1,'BFE', 2, true, 'dev'], number> // [1, 2]
type B = Filter<[1,'BFE', 2, true, 'dev'], string> // ['BFE', 'dev']
type C = Filter<[1,'BFE', 2, any, 'dev'], string> // ['BFE', any, 'dev']

2.伪代码

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

无法过测试案例中any

type C = Filter<[1, 'BFE', 2, any, 'dev'], string> // ['BFE', any, 'dev']

伪代码version0.1

//加个any判断不就好了
type Filter<T extends any[], A, R extends any[] = []> = T extends 
[infer F, ...infer Rest] ? 
F extends A | any
 ? Filter<Rest, A, [...R, F]> 
 : Filter<Rest, A, R>
: R;

还是不行,后面无法过测试用例,但是写的思路如下

  • Filter<T extends any[], A, R extends any[] = []>:定义一个名为Filter的泛型类型,它接受三个类型参数,分别为待过滤元组T、要筛选的类型A和结果元组RR的默认值为[]
  • T extends [infer F, ...infer Rest]:检查待过滤元组T是否非空。如果非空,使用类型推断来获取第一个元素F和剩余元素Rest
  • F extends A:检查元素F是否是类型A。如果是,则将其添加到结果元组R中,并继续递归处理剩余元素Rest。否则,跳过当前元素,仅处理剩余元素Rest
  • R:如果待过滤元组T为空,则表示已处理完所有元素。返回结果元组R

3.解决答案

type Filter<T extends any[], A, R extends A[] = []> = 
  T extends [infer F, ...infer O] 
    ? [F] extends [A]
      ? Filter<O, A, [...R, F]>
      : Filter<O, A, R>
    : R

思路解释

  1. Filter<T extends any[], A, R extends A[] = []>:定义一个名为Filter的泛型类型,它接受三个类型参数,分别为待过滤元组T、要筛选的类型A和结果元组RR的默认值为[]。注意,这里我们限制了R只能包含类型A的元素。
  2. T extends [infer F, ...infer O]:检查待过滤元组T是否非空。如果非空,使用类型推断来获取第一个元素F和剩余元素O
  3. [F] extends [A]:这是一个类型检查,用于判断元素F是否是类型A。将FA分别包装在元组中,然后利用元组的逐项类型检查。这样做的原因是,当涉及到泛型类型(如A)时,直接使用F extends A可能会导致预期之外的结果。包装在元组中可以更精确地进行类型检查。
  4. 如果类型检查结果为true,说明元素F是类型A,则将其添加到结果元组R中,并继续递归处理剩余元素O。否则,跳过当前元素,仅处理剩余元素O
  5. R:如果待过滤元组T为空,则表示已处理完所有元素。返回结果元组R