六维教程

TypeScript 数组与元组

上一节我们学习了基础类型,但实际开发中很少只处理单个值,我们经常需要处理一组数据,比如用户列表、商品标签、坐标点等。

TypeScript 提供了数组元组两种方式来描述这类数据结构。

一句话先记住区别

  • 数组:一组相同类型的数据,长度不固定
  • 元组:一组不同类型的数据,长度和位置固定

数组:相同类型的集合

定义方式

TypeScript 中定义数组有两种方式,推荐使用第一种,更简洁

// 方式一:类型 + 方括号(推荐)
let names: string[] = ["张三", "李四", "王五"];
let ages: number[] = [18, 20, 25];

// 方式二:泛型写法 Array<类型>
let names2: Array<string> = ["张三", "李四", "王五"];
let ages2: Array<number> = [18, 20, 25];

类型检查

添加了类型注解后,TypeScript 会阻止你放入错误类型的数据:

let names: string[] = ["张三", "李四"];
names.push("王五");   // ✅ 正确
names.push(123);      // ❌ 报错:不能将 number 赋值给 string
names[0] = 100;       // ❌ 报错

类型推断

如果省略类型注解,TypeScript 会根据初始值自动推断数组类型:

// 没有写类型注解,但 TypeScript 自动推断为 string[]
let fruits = ["苹果", "香蕉", "橙子"];

// 此时再推入数字会报错
fruits.push(123); // ❌ 报错

混合类型数组

如果数组需要同时包含多种类型,可以使用联合类型(后续章节会详细介绍):

// 数组里可以是 string 或 number
let mixed: (string | number)[] = ["张三", 25, "李四", 30];

数组常用操作

TypeScript 中的数组方法(mapfilterpush 等)都会自动保留类型信息:

const numbers: number[] = [1, 2, 3, 4, 5];

// map 返回的仍然是 number[]
const doubled = numbers.map(n => n * 2); // 推断为 number[]

// filter 返回的仍然是 number[]
const evens = numbers.filter(n => n % 2 === 0); // 推断为 number[]

// 处理混合类型时,配合类型保护更安全
const items: (string | number)[] = ["apple", 1, "banana", 2];
const strings = items.filter((item): item is string => typeof item === "string"); // 推断为 string[]

元组:固定结构的组合

元组是 TypeScript 特有的类型(JavaScript 没有),它用于表示元素数量和类型都固定的数据组合。

定义方式

// 定义元组:第一位是 string,第二位是 number,第三位是 boolean
let person: [string, number, boolean] = ["张三", 25, true];

// 访问元组元素
console.log(person[0]); // "张三"(类型为 string)
console.log(person[1]); // 25(类型为 number)

严格约束

元组对长度和每个位置的类型都有严格要求:

let person: [string, number] = ["张三", 25];

// ❌ 以下写法都会报错
person = ["张三"];          // 缺少第二个元素
person = ["张三", 25, true]; // 元素过多
person[0] = 100;            // 类型错误:不能将 number 赋值给 string

可选元素

元组中的某些元素可以是可选的(用 ? 标记),适合部分字段有值的情况:

// 第三个元素可选
let user: [string, number, boolean?] = ["张三", 25];
user = ["李四", 30, true];  // ✅ 也可以

// 访问可选的第三个元素
console.log(user[2]); // 类型为 boolean | undefined

实际使用场景

场景一:坐标点

// 经纬度 [经度, 纬度]
let location: [number, number] = [116.4, 39.9];

function getLocation(): [number, number] {
    return [116.4, 39.9];
}

场景二:API 响应(状态码 + 数据)

type ApiResponse = [number, string | null];

function fetchUser(): ApiResponse {
    if (Math.random() > 0.5) {
        return [200, "用户数据"];
    } else {
        return [500, null];
    }
}

const [code, data] = fetchUser();
if (code === 200) {
    console.log("成功:", data);
}

场景三:键值对

// 配置项 [键, 值]
let config: [string, string] = ["theme", "dark"];

常见问题

TypeScript 允许元组使用 push 方法添加元素,但这会破坏元组的长度约束

let person: [string, number] = ["张三", 25];
person.push("extra"); // ⚠️ TypeScript 不会报错!
// 但 person 实际变成了 ["张三", 25, "extra"]
// 违背了元组的初衷

原因:元组在编译后变成普通数组,push 方法存在于数组原型上,TypeScript 无法禁止调用。

建议:不要把元组当作数组使用,不要对元组调用 push / pop 等方法

数组 vs 元组:对比总结

对比维度 数组 元组
元素类型 必须统一 可以各不相同
长度 不固定,可增删 固定,不可变
使用场景 列表数据 固定结构的数据组合
示例 用户列表、标签集合 坐标 [x, y]、API 响应 [code, data]

选型建议

  • 数据是同类型的列表(如多个用户、多个商品)→ 用 数组
  • 数据是固定结构的组合(如经纬度、键值对)→ 用 元组
上一篇
TypeScript 基础类型
下一篇
TypeScript 枚举