题目
实现一个类型工具 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"];