TypeScript类型体操挑战(十八)

104 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

中等

Zip

挑战要求

在线示例

type Zip<T extends any[], U extends any[]> =
  T extends [infer F, ...infer E]
  ?
    U extends [infer F1, ...infer E1] 
    ? [[F, F1], ...Zip<E, E1>] 
    : []
  : []


// 使用示例:期望值为 [[1, true], [2, false]]
type exp = Zip<[1, 2], [true, false]>

我的解题思路如图:


解答区看到一个更简洁的答案:

type Zip<A extends any[], B extends any[], L extends any[] = []> = L['length'] extends A['length'] | B['length']
  ? L
  : Zip<A, B, [...L, [A[L['length']], B[L['length']]]]>
  • 主要就是使用L来存储每次处理好的值
  • 而每次处理的时候,L的长度刚好就是可以用来当AB的索引使用

IsTuple(判断元组类型)

挑战要求

在线示例

// 判断 never 类型
type IsNever<T> = [T] extends [never] ? true : false;

// 判断数组类型
type IsArray<T, U = number> = 
  T extends Array<U> 
    ? U extends T['length'] ? true : false 
  : false;

type IsTuple<T> = 
  IsNever<T> extends true 
  ? false 
  : IsArray<T> extends true 
    ? false 
    : T extends readonly [...any] ? true : false;

// 使用示例:
type A = IsTuple<[]> // true
type A = IsTuple<[number]> // true
type A = IsTuple<{ length: 1 }> // false
type A = IsTuple<number[]> // false

我的解题思路就是针对每个类型进行判断,层层过滤,然后得到答案。

  1. 使用IsNever判断never类型
// 为了能正确获取到 never 类型
// 所以将 T 变为了元组类型
type IsNever<T> = [T] extends [never] ? true : false;

  1. 使用IsArray判断数组类型,顺便也排除了对象{ length: 1 }
type IsArray<T, U = number> = 
  T extends Array<U> 
    ? U extends T['length'] ? true : false 
  : false;
  • U设置默认值是为了正确判断空数组。如果没有默认值,则U会是never,最后结果也会返回never

元组通过length属性得到的结果是数值,而数组类型得到的会是数组元素的类型:

// 结果为 3
type A = [1, 2, 3]['length'];

// 结果为 number
type B = number[]['length'];

  1. 到了最后判断一下是不是元组类型就好了
// 通过 rest 元素就可以判断啦
T extends readonly [...any] ? true : false;

我在解答区看到了一个非常简洁的答案:

type IsTuple<T> = 
  T extends readonly any[]
  ? number extends T['length'] ? false : true
  : false

对比起自己的,简直没眼看,但起码最后做出来了😭