typescript 类型体操 之 10-medium-tuple-to-union

346 阅读3分钟

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

前言

在学习typescript的过程当中,有一个github库对其类型的学习特别有帮助,是一个有点类似于leetcode的刷题项目,能够在里面刷各种关于typescript类型的题目,在上一篇文章中,我们完成了中等的第四题,今天来做中等的第五题 10-medium-tuple-to-union

下面这个是类型体操github仓库:

type-challenges/type-challenges: Collection of TypeScript type challenges with online judge (github.com)

10-medium-tuple-to-union

今天要来实现一个工具类型,将元组转为联合类型。

image.png

import type { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<TupleToUnion<[123, '456', true]>, 123 | '456' | true>>,
  Expect<Equal<TupleToUnion<[123]>, 123>>,
]

从测试用例和README能够清楚地知道,我们需要把元组中的元素拿出来,并且转为联合类型。

实现 TupleToUnion

infer 解法

对于数组来说,我们能够通过下标也就是数字索引来获取其中的属性:

type A1 = [1,2]

type A2 = A1[0]
// type A2 = 1

那么我们是否能够结合之前提过的 infer 关键字,能够通过 infer 和 rest 结合获取一个数组中的第一位和剩余位,这样一来,加上递归,就能够循环获取第一位,最后返回一个联合类型。

type TupleToUnion<T> = T extends [infer F, ... infer rest] ? F | TupleToUnion<rest> : never

type A1 = TupleToUnion<[1,2,boolean]>
// type A1 = boolean | 1 | 2

[key] 索引签名

我们能够通过索引签名的类型来获取索引签名的对应的类型:

type A1 = {
  [key:string]:1|2|3
}

type A2 = A1[string]
// type A2 = 1 | 2 | 3

并且当我们查看数组的key值时,就会发现:


type A4 = [1,2,3,true]

type A3 = {[P in keyof A4]:A4[P]}
// type A3 = {
//   [x: number]: true | 1 | 2 | 3;
//   0: 1;
//   1: 2;
//   2: 3;
//   3: true;
//   length: 4;
//   toString: () => string;
//   toLocaleString: () => string;
//   pop: () => true | 1 | 2 | 3 | undefined;
//   push: (...items: (true | 1 | 2 | 3)[]) => number;
//   ... 29 more ...;
//   at: (index: number) => true | ... 3 more ... | undefined;
// }

数组中也存在着一个索引签名,它的类型是number,并且对应了数组中所有属性的联合类型,那么,我们就能够利用上面这种更简单的方法,来获取数组中所有属性类型的联合类型。

type TupleToUnion<T extends unknown[]> = T[number]

type A5 = TupleToUnion<['s',2,3]>
// type A5 = 3 | "s" | 2

知识点

关于上述提到了部分的知识点:

  1. infer 关键字
  2. rest 参数
  3. 索引签名

infer 关键字和 rest 参数我们之前都有做过相关的题目,不清楚的话可以回顾一下之前的简单题,这里就不在过多描述。

索引签名的这种用法,我们这道题是第一次碰到,更加详细的描述,能够在官方文档中的索引签名里面找一下。

TypeScript: Documentation - Indexed Access Types (typescriptlang.org)

总结

今天我们做完了中等的第五题,题目的做法很多,本文主要列出了两种,剩余的可以自己去进行研究,最简单的做法应该就是 TS 提供给我们的索引签名去获取,这种方式简单又能够快速的获取数组的属性的类型的联合类型。