「TS类型体操00018」获取元组长度

167 阅读2分钟

题目

实现一个类型工具 Length<T>,其中T是一个元组类型,返回这个元组类型的长度。

例如:

// tesla 就是字面上 ['tesla', 'model 3', 'model X', 'model Y'] 这个类型
type tesla = ['tesla', 'model 3', 'model X', 'model Y']
// spaceX 就是字面上 ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT'] 这个类型
type spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT']

// teslaLength 得到字面量类型 4
type teslaLength = Length<tesla>
// spaceXLength 得到字面量类型 5
type spaceXLength = Length<spaceX>

原题链接

获取元组长度

思路

类比 JavaScript

类比 JavaScript,就是实现一个函数:

这个函数接收一个数组,返回这个数组的长度,如果接收到的不是数组,就抛出错误。

function getLength(arr) {
    if (!Array.isArray(arr)) {
        throw new TypeError(`Please pass an array.`);
    }
    return arr.length;
}

提取逻辑点

1. 返回数组的长度
2. 判断是否是数组
3. 数组还不够,必须得是元组 (TS自己的约束) 

再把逻辑点翻译成 TypeScript 即可。

翻译成 TypeScript

用 typescript 实现上述逻辑点如下。

返回数组的长度

通过 T["length"] 即可。

// tesla 类型是一个字面量类型,也是一个元组类型,写死了: 长度/类型元素位置/类型元素类型。
type tesla = ['tesla', 'model 3', 'model X', 'model Y']
// TLength 得到字面量类型 4, 也就是 tesla 元组类型的长度
type TLength = tesla["length"]

判断是否是数组

TypeScript 中,我们利用约束来达到判断的效果。

通过 T extends any[] 来让 T 必须是一个数组,这样别人在使用的时候,传递非数组类型就会报错,达到了目的。

type Length<T extends any[]> = T["length"];

数组还不够,必须得是元组 (TS自己的约束)

TypeScript 中,元组类型也就是定长定元素位置定元素类型数组类型

比如:

const fruits = ['apple', 'banana', 'orange'] as const;
// Cannot assign to '0' because it is a read-only property.ts(2540)
// 这时 fruits[0] 的类型已经被写死了 `apple`, 是不可以更改的了。
fruits[0] = 'grape';

要约束类型工具只接收元素,只需加上 readonly 使类型参数T只读:

T extends readonly any[]

实现

综上所述,最终的类型工具 TupleToObject 实现为:

type Length<T extends readonly any[]> = T["length"];