Typesctipt 定义定长列表的类型

5,884 阅读2分钟

前言

在平时需求中我们经常会遇到定义定长数组类型的需求

比如一个 9x9 的棋盘 model:

let board = [
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0],
];

我们知道 typescript 是支持设定一个数组类型的,那有没有办法设置一个定长的数组类型呢?

本体

首先我们来看一个简单的例子,定义一个 iMArray 的数组并把它的类型置为 number[]

let iMArray: number[] = [0, 1];

这是这种类型有个弊端,那就是我们并没法限制数组的长度:

iMArray.length = 3;
iMArray[3] = 1;

其中一种解决方式是使用元组来定义类型

let iMArray: [number, number] = [0, 1];

可以看到当我想对超出限定范围下标的数组元素进行赋值时, typescript 会给我们提示异常.

// boom
iMArray[3] = 1;

可是假如我们想定义一个长度限制在50的数组呢?难不成要写50遍 number?

不,解决办法还是有的,在 Typescript 3.0 中引入一个新的特性叫元组展开

假如我们想定义一个长度为 50 的数组, 我们只要这样写:

type Tuple50<TItem> = [TItem, ...TItem[]] & { length: 50 };

let iMArray: Tuple50<number> = [0,...,50];

可以看到,结合元组展开以及交叉类型,我们成功定义了一个长度为50,数组元素为 number 的数组.

回到前言提到的那个棋盘类,我们就可以这样定义一个9x9的棋盘类型了.

type Tuple9<TItem> = [TItem, ...TItem[]] & { length: 9 };

type TypeBoard<T> = Tuple9<Tuple9<T>>;

let board: TypeBoard<number> = [
    [0, ..., 9],
		...
    [0, ..., 9],
]

最后给一个封装好的 Tuple 类

type Tuple<TItem, TLength extends number> = [TItem, ...TItem[]] & { length: TLength };

参考

stackoverflow.com/questions/4…

github.com/Microsoft/T…

stackoverflow.com/questions/5…