在 TypeScript 中声明一个非空数组

使用元组类型中的剩余元素在 TypeScript 中声明一个非空数组,例如 let arr: [number, ...number[]] = [1]。 语法意味着数组包含一个数字的第一个元素,但数组是开放式的并且可能包含更多元素。

// ✅ Use an inline type
let arr: [number, ...number[]] = [1];

// ⛔️ Error: Source has 0 element(s) but target requires 1.ts(2322)
arr = [];

// ✅ Or use a type alias with a generic
type NonEmptyArr<T> = [T, ...T[]];

let arr2: NonEmptyArr<string> = ['a'];

arr2 = ['a', 'b']; // ✅ Works

// ⛔️ Error: Source has 0 element(s) but
// target requires 1.ts(2322)
arr2 = [];

在 TypeScript 中声明一个非空数组

我们使用最小长度为 1 的元组声明了一个非空数组。

第一个示例展示了如何声明一个非空数组,其中第一个元素是一个数字,并且可能包含零个或多个附加元素。

...number[] 语法在元组类型中称为 Rest 元素,表示元组是开放式的,并且可能有零个或多个指定类型的附加元素。

例如,[string, ...boolean[]] 表示一个元组,其第一个元素是字符串,后跟任意数量的布尔元素。

元组可以有超过 1 个元素,但如果我们尝试将其重新声明为空数组,则会出现错误。

let arr: [number, ...number[]] = [1];

// ⛔️ Error: Source has 0 element(s) but target requires 1.ts(2322)
arr = [];

元组类型用于表示具有固定数量元素的数组,这些元素的类型是已知的,但可以不同。

我们还可以使用类型别名来键入非空数组。

type NonEmptyArr<T> = [T, ...T[]];

let arr2: NonEmptyArr<string> = ['a'];

arr2 = ['a', 'b']; // ✅ Works

// ⛔️ Error: Source has 0 element(s) but
// target requires 1.ts(2322)
arr2 = [];

NonEmptyArr 类型是一个数组,它至少包含 1 个 T 类型元素,但可能有零个或多个 T 类型的附加元素。

在条件句中使用此类型别名可能会造成混淆:

type NonEmptyArr<T> = [T, ...T[]];

const arr3: string[] = ['a'];

function getArr(arr: NonEmptyArr<string>) {
  return arr;
}

if (arr3.length > 0) {
  // ⛔️ Error: Argument of type 'string[]' is not
  // assignable to parameter of type 'NonEmptyArr<string>'.
  getArr(arr3);
}

在 TypeScript 中声明一个非空数组

解决这个问题的最简单方法是使用类型断言。

type NonEmptyArr<T> = [T, ...T[]];


const arr3: string[] = ['a'];

function getArr(arr: NonEmptyArr<string>) {
  return arr;
}

if (arr3.length > 0) {
  // ✅ Works
  getArr(arr3 as NonEmptyArr<string>);
}

元组类型用于表示具有固定数量元素的数组,这些元素的类型是已知的,但可以不同。

话虽如此,元组由数组表示,我们仍然可以调用 pop() 方法从元组中删除元素。

const arr: [number, ...number[]] = [1];

arr.pop(); // ✅ OK

console.log(arr); // 👉️ []

如果要防止这种情况发生,可以将元组声明为 readonly

const arr: readonly [number, ...number[]] = [1];

// ⛔️ Error: Property 'pop' does not
// exist on type 'readonly [number, ...number[]]'.ts(2339)
arr.pop();

但这也意味着我们无法更改元组元素的值或添加更多元素。