数组、元组与枚举
本节目标
- 掌握数组的两种标注方式
- 理解「元组」和普通数组的区别及适用场景
- 搞懂
enum是什么、什么时候用、有什么坑
数组有两种写法,等价:
// 运行环境:Node.js 16+ + typescript;类型检查 npx tsc --noEmit ts-l4.ts
let nums: number[] = [1, 2, 3]
let nums2: Array<number> = [1, 2, 3] // 泛型写法,和上一行等价
// 数组里放错类型直接报错
// nums.push('x') // ❌ Argument of type 'string' is not assignable to 'number'**元组(Tuple)**是「长度固定、每个位置类型已知」的数组,适合表达「有明确结构的一对小值」:
// 表示「用户名 + 年龄」这样一对固定结构
let user: [string, number] = ['Laowen', 30]
// user = ['Laowen'] // ❌ 少一个元素报错
// user = [30, 'Laowen'] // ❌ 顺序错了也报错
// 实际应用:React 的 useState 返回的就是 [值, 设值函数] 元组
function useFakeState<T>(init: T): [T, (v: T) => void] {
let value = init
const setter = (v: T) => { value = v }
return [value, setter]
}
const [name, setName] = useFakeState('guest')
console.log(name) // guest**枚举(enum)**给一组相关常量起名字:
// 用 enum 表达「订单状态」
enum OrderStatus {
Pending = 'pending',
Paid = 'paid',
Shipped = 'shipped',
}
const status: OrderStatus = OrderStatus.Paid
console.log(status) // 'paid'⚠️ 坑:enum 在编译后会生成一段「运行时代码」(不是纯类型),而且默认数字枚举会「反向映射」。现代 TS 更推荐用 as const 对象或联合类型替代枚举(见下一节),更轻量、更透明。
名词解释
元组(Tuple):一种「定长且每格类型固定」的数组。普通数组 number[] 要求每个元素都是 number 且个数不限;元组 [string, number] 要求「第 0 个是 string、第 1 个是 number、且只有 2 个」。它适合表达「成对出现的结构化数据」,好比一张两列的表格的一行。
枚举(Enum):把一组「有意义的名字」映射到「值」的工具,让代码里不出现魔法字符串/数字。比如用 OrderStatus.Paid 比直接写 'paid' 更安全、更易读。但要记住它会在运行时真实存在。
课后练习
练习 1:用元组表示一个「经纬度坐标 [number, number]」,并写一个函数判断它是否在原点。
答案:
type Point = [number, number] function isOrigin(p: Point): boolean { return p[0] === 0 && p[1] === 0 }
练习 2:既然 enum 有运行时开销,如何用「联合类型 + as const」表达订单状态更安全?
答案:
const OrderStatus = { Pending: 'pending', Paid: 'paid', Shipped: 'shipped', } as const type OrderStatus = typeof OrderStatus[keyof typeof OrderStatus] // 'pending' | 'paid' | 'shipped'
总结
我认为元组是被低估的类型:凡是「两个或三个相关值、且位置有意义」的场景(坐标、键值对、useState 返回值),用元组比用对象更简洁,而且解构赋值读起来很舒服。至于枚举,我的态度是能不用就不用——数字枚举的反向映射和运行时体积常常带来惊喜(贬义)。现在社区主流做法是用 as const 对象 + 从它推导出的联合类型,零运行时成本、IDE 提示还一样好。只有在和既有 JS/第三方库强绑定时,才退而用 enum。