TypeScript类型体操挑战(五)

163 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

中等

最后一个元素

挑战要求

在线示例

type Last<T extends readonly any[]> = T extends [...infer R, infer L] ? L : T;
  • 因为元组支持rest元素,所以通过extends搭配infer就可以获取到最后一个元素的类型了

解答区看到一个👍比较多的答案,我的答案兼职low爆了:

type Last<T extends any[]> = [any, ...T][T["length"]];
  • 首先通过[any, ...T]组成了一个新的元组类型
  • 使用索引访问类型可以获取对应的属性,只要是数组上的属性,都可以使用:

TS是可以推断出元组类型的长度的,所以T["length"]是可以获得具体数值的,从而获取最后一个元素的类型。

例子:

type A = Last<[1, 2, 3]>

// 相当于
type A = [any, 1, 2, 3][3]

出堆

挑战要求

在线示例

type Pop<T extends any[]> = T extends [...infer R, any] ? R : T;
  • extends是跟infer搭配使用的
  • 通过rest元素组成新的元组

额外的:实现ShiftPushUnshift

type Shift<T extends any[]> = T extends [any, ...infer R] ? R : T;
type Push<T extends any[], K> = [...T, K];
type Unshift<T extends any[], K> = [K, ...T];
  • 道理就跟上面差不多了,利用的都是元组的特性

Promise.all

挑战要求

在线示例

type TupleType<T extends any[]> = {
  [P in keyof T]: T[P] extends Promise<infer R> ? R : T[P]
} 

declare function PromiseAll<T extends any[]>(values: readonly [...T]): Promise<TupleType<T>>
  • [...T]的目的就是使用rest元素创建一个元组类型,看个例子:
type A<T extends any[]> = [...T]

type B = A<[1, 2, 3]>
// 相当于:
type B = [1, 2, 3]
  • 而使用readonly修饰[...T]就变成了只读元组类型
  • 最后就是通过TupleType来遍历元组,把元组中的元素类型按照条件进行处理

Type Lookup

挑战要求

在线示例

type LookUp<U, T extends string> = U extends { type: T } ? U : never;

例子:

type Animal = Cat | Dog

LookUp<Animal, 'dog'>

因为使用泛型U的时候传入联合类型,所以搭配上extends就变成了分布类型,相当于:

Cat extends { type: T } ? Cat : never | Dog extends { type: T } ? Dog : never

类型结构之间,参数少的兼容参数多的,所以通过{ type: T }这个结构就可以获得想要的结果了。