TS 数组

753 阅读4分钟

TypeScript 提供了多种方式来定义和使用数组类型,确保数组元素的类型安全。

我们在使用中数组中一般存放相同的类型

1. 基本语法:Type[]

这是最常用、最简洁的定义数组类型的方式。它表示一个数组,其所有元素都必须是指定的 Type 类型。

// 定义一个只包含数字的数组
let numbers: number[];
numbers = [1, 2, 3, 4, 5];
// numbers = [1, "two", 3]; // Error: Type 'string' is not assignable to type 'number'.
numbers.push(6);
// numbers.push("seven"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.

// 定义一个只包含字符串的数组
let names: string[] = ["Alice", "Bob", "Charlie"];

// 定义一个只包含布尔值的数组
let flags: boolean[] = [true, false, true];
    

2. 泛型数组语法:Array<Type>

这是另一种等效的定义数组类型的方式,使用了泛型(Generics)。Array 和 Type[] 在功能上是完全相同的。

let scores: Array<number> = [100, 95, 88];
let messages: Array<string> = ["hello", "world"];
let results: Array<boolean> = [true, false];

// scores.push("A+"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.
    

选择哪种语法?
通常 Type[] 语法更受欢迎,因为它更简洁。但在处理复杂的泛型类型时,Array 可能在某些情况下更具可读性。两者可以互换使用。

3. 包含联合类型的数组

数组的元素可以是多种类型之一,这时使用联合类型。

// 数组元素可以是 number 或 string
let mixedArray: (number | string)[];
mixedArray = [1, "two", 3, "four"];
mixedArray.push(5);
mixedArray.push("six");
// mixedArray.push(true); // Error: Argument of type 'boolean' is not assignable to type 'string | number'.

// 使用泛型语法
let mixedArrayGeneric: Array<number | string>;
mixedArrayGeneric = mixedArray;
    

4. 包含对象或其他复杂类型的数组

数组的元素可以是对象、接口、类型别名或其他复杂类型。

interface Point {
  x: number;
  y: number;
}

// Point 对象的数组
let points: Point[] = [
  { x: 0, y: 0 },
  { x: 10, y: 20 },
  // { x: 5 } // Error: Property 'y' is missing in type '{ x: number; }' but required in type 'Point'.
];

type User = {
  id: number;
  name: string;
};

// User 类型别名对象的数组
let users: User[] = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
];
    

5. 元组类型 (Tuple Types)

元组类型允许你定义一个元素数量固定每个位置上的元素类型已知的数组。它与普通数组的主要区别在于长度和元素类型的固定性。

// 定义一个元组:第一个元素是 string,第二个是 number
let personInfo: [string, number];

personInfo = ["Alice", 30]; // OK
// personInfo = [30, "Alice"]; // Error: Type 'number' is not assignable to type 'string'. Type 'string' is not assignable to type 'number'.
// personInfo = ["Bob", 40, true]; // Error: Type '[string, number, boolean]' is not assignable to type '[string, number]'. Source has 3 element(s) but target allows only 2.
// personInfo = ["Charlie"]; // Error: Type '[string]' is not assignable to type '[string, number]'. Source has 1 element(s) but target requires 2.

// 访问元组元素时,会得到对应位置的精确类型
let personName: string = personInfo[0];
let personAge: number = personInfo[1];
// let unknown = personInfo[2]; // Error: Tuple type '[string, number]' of length '2' has no element at index '2'.

// 元组也支持可选元素 (?) 和剩余元素 (...)
let optionalTuple: [string, number?]; // 第二个元素可选
optionalTuple = ["Dave"];
optionalTuple = ["Eve", 25];

let restTuple: [string, ...number[]]; // 第一个是 string,后面是任意数量的 number
restTuple = ["Scores", 100, 95, 88];
restTuple = ["ID"]; // 也满足,剩余部分为空数组 []
    

6. 只读数组 (Readonly Arrays)

如果你希望创建一个数组,其内容在创建后不能被修改(增加、删除、替换元素),可以使用 readonly 修饰符。

有两种语法:

  • readonly Type[]
  • ReadonlyArray (泛型)
const readonlyNumbers: readonly number[] = [1, 2, 3];
const readonlyMessages: ReadonlyArray<string> = ["Read", "Only"];

// readonlyNumbers[0] = 5; // Error: Index signature in type 'readonly number[]' only permits reading.
// readonlyNumbers.push(4); // Error: Property 'push' does not exist on type 'readonly number[]'.
// readonlyNumbers.pop();   // Error: Property 'pop' does not exist on type 'readonly number[]'.
// readonlyNumbers.length = 0; // Error: Cannot assign to 'length' because it is a read-only property.

// 注意:readonly 只保证数组本身的结构不可变,
// 如果数组元素是对象,对象内部的属性仍然可以修改。
interface Config { setting: string; }
const readonlyConfigs: readonly Config[] = [{ setting: 'on' }];
readonlyConfigs[0].setting = 'off'; // 这是允许的!readonly 只限制数组操作。
    

如果你想让对象本身也只读,需要使用 Readonly 等更深层次的只读类型。

7. 类型推导 (Type Inference)

当你初始化数组时,TypeScript 通常能自动推断出数组的类型。

// 推断为 number[]
let inferredNumbers = [10, 20, 30];

// 推断为 string[]
let inferredStrings = ["a", "b", "c"];

// 推断为 (string | number)[]
let inferredMixed = [1, "hello", 3];
    

总结:

TypeScript 提供了强大且灵活的方式来定义数组类型:

  • Type[] 和 Array 用于元素类型统一的普通数组。
  • 联合类型 (TypeA | TypeB)[] 用于元素类型可以是多种之一的数组。
  • 元组 [TypeA, TypeB] 用于长度固定、各位置类型已知的数组。
  • readonly 修饰符用于创建不可变的数组结构。