元组是一种固定长度、元素类型确定的数组。与普通数组不同,元组中每个位置的元素类型是固定的。
let tuple: [string, number] = ["张三", 25]
console.log(tuple[0]) // "张三" - string 类型
console.log(tuple[1]) // 25 - number 类型
元组中每个位置的元素类型是确定的:
let user: [string, number, boolean] = ["张三", 25, true]
let name: string = user[0] // 正确
let age: number = user[1] // 正确
let active: boolean = user[2] // 正确
let wrong: string = user[1] // 错误:类型不匹配
访问已知索引是安全的:
let tuple: [string, number] = ["hello", 10]
console.log(tuple[0].toUpperCase()) // "HELLO" - string 方法
console.log(tuple[1].toFixed(2)) // "10.00" - number 方法
let tuple: [string, number?] = ["张三"]
console.log(tuple.length) // 1
tuple[1] = 25
console.log(tuple.length) // 2
let tuple: [string, ...number[]] = ["张三", 1, 2, 3, 4, 5]
console.log(tuple[0]) // "张三"
console.log(tuple.slice(1)) // [1, 2, 3, 4, 5]
let readonlyTuple: readonly [string, number] = ["张三", 25]
readonlyTuple[0] = "李四" // 错误:只读
readonlyTuple.push(30) // 错误:只读
function getUserInfo(): [string, number, boolean] {
return ["张三", 25, true]
}
const [name, age, isActive] = getUserInfo()
console.log(name, age, isActive) // 张三 25 true
let entries: [string, number][] = [
["apple", 5],
["banana", 3],
["orange", 4]
]
let map = new Map(entries)
console.log(map.get("apple")) // 5
type Point = [number, number]
type Point3D = [number, number, number]
let point2D: Point = [10, 20]
let point3D: Point3D = [10, 20, 30]
function distance(a: Point, b: Point): number {
return Math.sqrt(
Math.pow(b[0] - a[0], 2) + Math.pow(b[1] - a[1], 2)
)
}
console.log(distance([0, 0], [3, 4])) // 5
type RGB = [number, number, number]
function toHex(rgb: RGB): string {
return "#" + rgb
.map(n => n.toString(16).padStart(2, "0"))
.join("")
}
console.log(toHex([255, 128, 0])) // #ff8000
type TableRow = [number, string, number, string]
const rows: TableRow[] = [
[1, "苹果", 5, "水果"],
[2, "白菜", 3, "蔬菜"],
[3, "牛肉", 50, "肉类"]
]
function renderTable(rows: TableRow[]): string {
return rows.map(row => row.join(" | ")).join("\n")
}
console.log(renderTable(rows))
// 1 | 苹果 | 5 | 水果
// 2 | 白菜 | 3 | 蔬菜
// 3 | 牛肉 | 50 | 肉类
let user: [string, number] = ["张三", 25]
let [name, age] = user
console.log(name, age) // 张三 25
let [first, ...rest]: [number, number, number, number] = [1, 2, 3, 4]
console.log(first) // 1
console.log(rest) // [2, 3, 4]
元组本质上是数组,可以使用数组方法:
let tuple: [string, number] = ["张三", 25]
console.log(tuple.length) // 2
console.log(tuple.concat(["李四", 30])) // ["张三", 25, "李四", 30]
tuple.push("extra") // 可以添加,但不推荐
console.log(tuple) // ["张三", 25, "extra"]
| 特性 | 元组 | 数组 |
|---|---|---|
| 长度 | 固定 | 可变 |
| 元素类型 | 每个位置确定 | 所有元素相同 |
| 访问 | 索引类型确定 | 所有元素类型相同 |
let array: number[] = [1, 2, 3]
array.push(4) // 正确
let tuple: [number, number] = [1, 2]
tuple.push(3) // 可以,但不推荐
let tuple: [string, number] = ["张三", 25]
tuple = ["李四"] // 错误:缺少元素
tuple = ["李四", 30, true] // 错误:元素过多
let tuple: [string, number] = ["张三", 25]
tuple[0] = 123 // 错误:类型不匹配
tuple[1] = "30" // 错误:类型不匹配
let tuple: [string, number] = ["张三", 25]
let third = tuple[2] // 类型为 undefined,但不会报错
TypeScript 4.0+ 支持元组标签:
type UserTuple = [name: string, age: number, active: boolean]
function createUser(tuple: UserTuple): void {
const [name, age, active] = tuple
console.log(name, age, active)
}
createUser(["张三", 25, true])