阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 数组与元组类型

数组与元组类型

作者:陈川 阅读数:22127人阅读 分类: TypeScript

TypeScript 提供了多种方式描述结构化数据,其中数组和元组是最基础的两种复合类型。它们都能存储有序元素集合,但在使用场景和类型约束上存在显著差异。

数组类型基础

数组类型表示由相同类型元素组成的可变长度序列。TypeScript 提供了两种等效的语法声明数组类型:

// 元素类型后接方括号
let numbers: number[] = [1, 2, 3];

// 使用泛型数组类型
let strings: Array<string> = ["a", "b"];

数组类型会强制所有元素保持类型一致。当尝试混合类型时,TypeScript 会抛出错误:

// 类型错误:不能将字符串分配给数字数组
numbers.push("4"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'

数组类型推断

TypeScript 能根据初始化值自动推断数组类型。空数组需要显式注解,否则会被推断为 any[]

let inferredArray = [1, 2, 3]; // 自动推断为 number[]
let emptyArray = []; // 类型为 any[]
let typedEmptyArray: string[] = []; // 显式注解

只读数组

使用 ReadonlyArrayreadonly 修饰符可以创建不可变数组:

const roArray: ReadonlyArray<number> = [1, 2, 3];
roArray.push(4); // Error: Property 'push' does not exist on type 'ReadonlyArray<number>'

// 使用更简洁的语法
const roNumbers: readonly number[] = [1, 2, 3];

元组类型基础

元组类型允许表示已知元素数量和类型的数组,各元素的类型不必相同:

let person: [string, number] = ["Alice", 30];

元组严格校验元素位置和类型:

person = [30, "Alice"]; // Error: Type 'number' is not assignable to type 'string'
person[2] = true; // Error: 长度为 "2" 的元组类型 "[string, number]" 在索引 "2" 处没有元素

可选元组元素

元组可以通过问号标记可选元素:

type OptionalTuple = [string, number?];
const a: OptionalTuple = ["hello"]; // 合法
const b: OptionalTuple = ["world", 42]; // 合法

剩余元素与开放元组

元组可以使用剩余语法表示可变长度部分:

type StringNumberBooleans = [string, number, ...boolean[]];
const snb: StringNumberBooleans = ["hello", 1, true, false, true];

元组与数组的区别

  1. 长度处理
// 数组长度可变
const arr: number[] = [1];
arr.push(2); // 合法

// 元组长度固定
const tuple: [number] = [1];
tuple.push(2); // 类型检查通过但违反元组设计初衷
  1. 解构行为
const rgb: [number, number, number] = [255, 0, 128];
const [red, green, blue] = rgb; // 精确解构

const color = [255, 0, 128]; // number[] 类型
const [r, g, b] = color; // 解构后类型均为 number

实际应用场景

数组典型用例

// 处理同质数据集合
function sum(values: number[]): number {
  return values.reduce((a, b) => a + b, 0);
}

元组典型用例

// React useState 返回类型
type StateHook<T> = [T, (newValue: T) => void];

function useState<T>(initial: T): StateHook<T> {
  // 实现省略
}

// CSV 行处理
function parseCSVLine(line: string): [string, number, Date] {
  // 解析逻辑
  return ["Alice", 30, new Date()];
}

类型操作与高级特性

联合类型数组

let mixedArray: (string | number)[] = ["text", 42];

常量断言

const point = [10, 20] as const; // 类型为 readonly [10, 20]

映射类型转换

type TupleToObject<T extends readonly any[]> = {
  [K in keyof T]: { value: T[K] }
};

type ObjTuple = TupleToObject<[string, number]>; 
// 结果为 [{ value: string }, { value: number }]

常见问题与解决方案

元组长度溢出

function processTuple(t: [string, number]) {
  // ...
}

const input = ["test", 1, "extra"] as const;
processTuple(input); // Error: 源具有 3 个元素,但目标仅允许 2 个

// 解决方案1:类型断言
processTuple(input as [string, number]);

// 解决方案2:精确类型定义
function processDynamicTuple(t: readonly [string, number, ...unknown[]]) {
  const [first, second] = t;
  // ...
}

变异数组成员

const tuple: [string, number] = ["a", 1];
tuple[0] = "b"; // 合法但可能不符合设计预期

// 防御性方案
type ImmutableTuple = readonly [string, number];
const immutable: ImmutableTuple = ["a", 1];
immutable[0] = "b"; // Error: 无法分配到 "0",因为它是只读属性

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌