在掌握了 string、number 和 boolean 这些基本类型后,我们自然会遇到下一个问题:当需要处理一组同类型的数据时,应该怎么办?例如,一个文章标签列表,或者一个用户 ID 集合。
在 JavaScript 中,我们会毫不犹豫地使用数组。TypeScript 继承了这一核心概念,并在此基础上提供了更强的类型安全保障。同时,它还引入了一个新的、更为严格的集合类型——元组 (Tuple)。
数组 (Array):灵活的同类型集合
在 TypeScript 中,数组是一个有序的元素列表,其核心特征是数组内的所有元素都应具有相同的类型。如果我们尝试向一个数字数组中添加字符串,TypeScript 编译器会立即发出警告。
声明数组的两种方式
我们有两种主要的方式来声明一个数组类型:
类型 + 方括号
[]这是最直观和常用的语法。在元素类型后面跟上一对方括号,表示这是一个由该类型元素组成的数组。
typescript// 声明一个字符串数组 let tags: string[]; // 声明一个数字数组 let postIds: number[]; tags = ["typescript", "frontend", "development"]; postIds = [101, 102, 105];泛型数组类型
Array<Type>第二种方式是使用泛型(Generics)。通过
Array<Type>的语法同样可以定义一个数组,它与Type[]在功能上是完全等价的。typescript// 声明一个数字数组 let postIds: Array<number>; // 声明一个布尔值数组 let statuses: Array<boolean>; postIds = [201, 202, 205]; statuses = [true, false, true];虽然两种方式等效,但在代码可读性上,
Type[]通常更简洁。而当处理更复杂的嵌套数组时(例如Array<Array<string>>),泛型语法有时能提供更好的清晰度。
数组的类型安全实践
TypeScript 数组的价值体现在它如何防止我们犯错。一旦数组的类型被确定,任何“出格”的操作都会被拦截。
let highScores: number[] = [98, 95, 100];
// 合法操作:添加同类型元素
highScores.push(99);
// 访问元素,其类型是可预知的 number
let firstScore: number = highScores[0];
// 非法操作:尝试添加一个不同类型的元素
// highScores.push("97"); // 错误:类型“string”的参数不能赋给类型“number”的参数。这种在编码阶段的即时反馈,极大地提升了代码的健壮性。
元组 (Tuple):精准控制的异构集合
现在,我们来思考一个场景:我们需要一个变量来存储一本书的信息,包含书名(string)和出版年份(number)。
如果使用数组,我们可能会这样定义:let book: (string | number)[] = ["Thinking in TypeScript", 2024]。这个定义虽然没有错,但它丢失了重要的信息:
- 长度信息:这个数组应该只有两个元素。
- 位置信息:第一个元素必须是字符串,第二个必须是数字。
为了解决这类问题,TypeScript 引入了元组 (Tuple)。
元组可以被看作是一种特殊的数组,它具有固定的长度和在每个位置上确定的类型。
定义与使用元组
元组的类型定义看起来就像一个包含类型的数组字面量:
// 定义一个元组类型
// 它表示一个有两个元素的集合
// 第一个元素是 string 类型,第二个是 number 类型
let bookInfo: [string, number];
// 正确赋值
bookInfo = ["The Pragmatic Programmer", 1999];
// 错误:顺序不匹配
// bookInfo = [1999, "The Pragmatic Programmer"]; // 错误:不能将类型“number”分配给类型“string”。
// 错误:长度不匹配
// bookInfo = ["Designing Data-Intensive Applications"]; // 错误:源具有 1 个元素,但目标需要 2 个。通过元组,我们为原本无序、同构的数组赋予了
