TypeScript 中的元组(Tuple)详解
元组(Tuple) 是 TypeScript 对数组的增强类型,它允许你定义一个元素数量固定且每个元素类型可能不同的数组。普通数组(如 number[])要求所有元素类型相同,且长度不固定,而元组正好解决了“固定结构”的需求。
1. 基本声明与使用
// 声明一个包含 string 和 number 的元组
let person: [string, number] = ["Alice", 30];
// 访问元素(类型安全)
let name: string = person[0]; // "Alice"
let age: number = person[1]; // 30
// person[2] = "extra"; // 错误:索引越界,TS 会报错
// person = ["Bob", "25"]; // 错误:第二个元素必须是 number
// person = ["Charlie"]; // 错误:长度不足,必须正好 2 个元素
2. 类型推断
大多数情况下可以省略显式类型注解,TS 会自动推断:
let tuple = ["Bob", 25, true];
// 类型被推断为 [string, number, boolean]
// 一旦推断后,类型和长度固定
tuple[1] = "twenty"; // 错误:必须是 number
tuple.push("extra"); // 注意:push 不会报错!(TS 局限性,见下文)
3. 可选元素(TS 4.0+)
元组的后续元素可以标记为可选(必须放在末尾):
let optionalTuple: [string, number?] = ["Charlie"]; // OK,只有一个元素
optionalTuple = ["Dave", 28]; // OK,有两个元素
// optionalTuple = ["Eve", 30, true]; // 错误:超出可选范围
4. 剩余元素(Rest Elements,TS 4.2+)—— 可变长度元组
使用展开运算符允许末尾元素为数组(不定长度):
// 前两个固定,后续为任意数量的 number
let scores: [string, number, ...number[]] = ["Math", 95];
scores = ["English", 88, 92, 85]; // OK
// 访问
let subject: string = scores[0];
let baseScore: number = scores[1];
let extraScores: number[] = scores.slice(2);
5. 只读元组
防止元组被修改:
let readonlyTuple: readonly [string, number] = ["Fixed", 100];
// readonlyTuple[0] = "Change"; // 错误:只读
// readonlyTuple.push(200); // 错误:没有 push 方法
6. 常见应用场景
元组非常适合表示固定结构的数据:
// 1. 坐标点
type Point = [number, number];
let origin: Point = [0, 0];
// 2. RGB 颜色
type Color = [number, number, number];
let red: Color = [255, 0, 0];
// 3. HTTP 响应
type HttpResponse = [number, string]; // [statusCode, body]
let success: HttpResponse = [200, "OK"];
let notFound: HttpResponse = [404, "Not Found"];
// 4. 函数返回多个值
function getUserInfo(): [string, number, boolean] {
return ["Alice", 30, true];
}
let [username, userAge, isAdmin] = getUserInfo(); // 解构赋值
7. 注意事项与局限性
- push/pop 等方法不会被类型检查限制:
let tuple: [string, number] = ["A", 1];
tuple.push(2); // 不会报错!运行时长度变为 3
解决方案:使用 as const 或 readonly 防止修改:
let safeTuple = ["A", 1] as const; // 类型为 readonly ["A", 1]
// safeTuple.push(2); // 错误
- 标签元组(Labeled Tuples,TS 4.0+) —— 提高可读性(仅用于文档,不影响类型):
type Person = [name: string, age: number, isActive: boolean];
let p: Person = ["Bob", 25, true]; // 标签提示更清晰
8. 元组 vs 普通数组 vs 对象
| 类型 | 长度 | 元素类型 | 推荐场景 |
|---|---|---|---|
number[] | 可变 | 统一 | 同类型元素列表(如成绩列表) |
[string, number] | 固定 | 可不同 | 固定结构数据(如坐标、键值对) |
{ name: string; age: number } | – | 可不同 | 复杂对象,属性多且有意义名称 |
何时选元组:当你需要一个小型、固定顺序的异构集合,且不需要属性名时。
小结:元组类型速查
| 写法 | 含义 | 示例 |
|---|---|---|
[string, number] | 固定 2 元素 | ["Alice", 30] |
[number, number?] | 第二个可选 | ["x", 10] 或 ["x"] |
[string, ...number[]] | 第一个固定,后续任意数量 number | ["scores", 90, 85] |
readonly [string, boolean] | 只读元组 | ["status", true] as const |
as const | 将数组字面量转为只读元组 | let t = [1, "hi"] as const; |
如果您想看更多实际示例(如解构元组、元组在函数参数中的使用、与接口的结合),或者想了解元组与联合类型的高级玩法,请告诉我!