TypeScript中的非空数组

1,858 阅读3分钟

今天写项目的时候,有个数组不能为空,那么在TS中如何实现一个非空数组呢?

既然是非空数组,便存在两条限制,第一个是数组里元素的类型,第二个则是数组的length。

首先是定义类型 type noBlankArr = []

但是这个类型并非“非空数组”,而是arr.length === 0的必空数组类型,他不能包含任何元素。

既然我们想要的是“非空”数组,首当其冲的也就是我们并不知道这个数组里元素的类型,我们先解决类型这个问题。这时我想到泛型(我把泛型+类型定义视作函数+形参的功能)

因此第二步我的思路是 type noBlankArr<T> = []

噢~,到目前为止他仍然是一个arr.length === 0的数组类型,只不过在使用这个类型的时候,他必须接受一个泛型

下面是栗子~

 let foo:noBlankArr<string> //success
 
 let bar:noBlankArr  //error

也就是这种情况下一旦定义泛型,那么使用的时候就一定要赋予这个泛型“实参”;在这个例子中实参是string,到目前为止算是解决了元素类型的问题~

那么机智的我和聪明的你一定都想到了next step(下一步)

既然泛型一定要被使用,那和我们所期望的,数组里一定要有元素不是一样吗?所以,我们把泛型(在这里是T),放到数组里~

type noBlankArr<T> = [T]

let arr1:noBlankArr<number> = [1] // success
let arr2:noBlankArr<number> = [] // error
let arr3:noBlankArr<number> = [1,2,3] // error

现在这就是一个非空数组啦~ 但是我们可以看到上面的第三条例子,被目前这个type定义的变量,是仅仅必须且只能拥有一个元素的数组,因为我们只放入了一个T在数组里,即[T]。很明显这是个非常严重的bug!!!

但是解决方案也非常简单

这是答案:type noBlankArr<T> = [T,...T[]],他是怎么实现的呢?拆分[T,...T[]]这块代码,

  • 第一个泛型T代表的是“一定要拥有至少一个类型T的元素

  • ...T[]代表的解构一个类型是类型是T的数组并且这个数组可以为空数组

说的我自己都觉得有点抽象,先暂停,看下面这段代码

type noBlankArr<T> = [...T[]]
let arr1:noBlankArr<number> = [] //success
let arr2:noBlankArr<number> = [1,2,3,4] //success

也就说[...T[]],是能实现类型是T 且 任意数量的数组并将其结构,那么最后补充上第一个必须拥有的T吧,综合以上~这样就实现了被限制了类型和length >= 1的非空数组.

最后回到我们的答案type noBlankArr<T> = [T,...T[]],验证一下,总不能写出来的东西报错吧~天呐 那就芭比q了 不是吗?

type noBlankArr<T> = [T,...T[]]

let arr:noBlankArr<string> = ['2']  //success

let arr2:noBlankArr<string> = []   //error

当然,如果你非常懒,以及没有那么追求对变量的严格要求类型,你可以这么做

type noBlankArr = [any,...any[]]

这样会对变量进行自动的类型推断了~

the end ~