数组和元组:处理集合数据
欢迎继续本专栏的第四篇文章。在前几期中,我们已掌握 TypeScript 的基本类型和开发环境设置。今天,我们将转向集合数据的处理,重点探讨数组和元组。这两种结构是管理多元素数据的关键工具。通过类型注解,它们能确保数据一致性和安全性。我们将从数组的基础定义开始,逐步引入元组、readonly 修饰符,并结合实际应用场景,帮助您构建更可靠的代码。内容将逐步展开,确保您能从简单示例过渡到深入理解。
数组的基础:定义与类型注解
数组是 TypeScript 中最常见的集合类型,用于存储有序的元素列表。它继承自 JavaScript 的 Array,但通过类型系统,您可以指定元素类型,从而避免混合数据导致的错误。
-
基本声明:
-
语法有两种:使用方括号或 Array 泛型。
typescriptlet numbers: number[] = [1, 2, 3]; // 指定元素为 number let strings: Array<string> = ["apple", "banana"]; // 等价于 string[] -
未初始化时,可声明为空数组:
typescriptlet empty: number[] = []; // 空数组,稍后可添加 number 元素
-
-
赋值与操作:
-
添加元素:使用 push 方法,但必须匹配类型。
typescriptnumbers.push(4); // 有效 // numbers.push("five"); // 错误:字符串不可赋值为 number[] -
访问元素:通过索引,确保边界检查。
typescriptlet first: number = numbers[0]; // 1 -
常见方法:如 map、filter 和 reduce,用于变换数组。
typescriptlet doubled: number[] = numbers.map(n => n * 2); // [2, 4, 6, 8] let evens: number[] = numbers.filter(n => n % 2 === 0); // [2, 4] let sum: number = numbers.reduce((acc, curr) => acc + curr, 0); // 10
-
数组的类型注解在处理统一数据时特别有用,如数值列表或字符串集合。它防止了 JavaScript 中常见的类型混淆问题。
引入 readonly 修饰符:保护数组免于修改
在某些场景中,您可能希望数组不可变,以避免意外更改。TypeScript 提供了 readonly 修饰符,它标记数组为只读,允许读取但禁止修改。
-
声明 readonly 数组:
-
语法:在类型前添加 readonly。
typescriptlet readonlyNumbers: readonly number[] = [1, 2, 3]; // 或使用 ReadonlyArray<number> -
这确保了数组内容固定:
typescriptlet value: number = readonlyNumbers[0]; // 有效,读取允许 // readonlyNumbers.push(4); // 错误:readonly 数组不可修改 // readonlyNumbers[0] = 10; // 错误:索引赋值禁止
-
-
与 const 的区别:
-
const 保护变量引用(不能重新赋值整个数组),但允许修改内部元素。
typescriptconst mutable: number[] = [1, 2]; mutable.push(3); // 有效 -
readonly 则锁定内部结构,常用于配置数据或函数参数。
typescriptfunction process(data: readonly string[]) { // data.push("new"); // 错误 console.log(data.join(", ")); // 有效 }
-
readonly 提升了代码的不可变性,减少了副作用,尤其在函数式编程中。
元组:固定长度与类型的数组
当数组需要固定长度且每个位置类型不同时,元组(tuple)是理想选择。它是数组的变体,但指定了确切元素数量和类型。
-
定义与注解:
-
使用方括号内逗号分隔类型。
typescriptlet person: [string, number] = ["Alice", 30]; // 第一元素 string,第二 number // let invalid: [string, number] = ["Alice", "30"]; // 错误:字符串不可为 number // let tooLong: [string, number] = ["Alice", 30, true]; // 错误:长度超限
-
-
访问与解构:
-
通过索引访问,确保类型匹配。
typescriptlet name: string = person[0]; let age: number = person[1]; -
解构赋值更简洁:
typescriptlet [userName, userAge] = person; // userName: string, userAge: number
-
-
可选元素与 readonly:
-
支持可选元素,使用 ?。
typescriptlet coords: [number, number, number?] = [10, 20]; // 第三个可选 coords = [10, 20, 30]; // 也有效 -
结合 readonly:
typescriptlet readonlyPerson: readonly [string, number] = ["Bob", 25]; // readonlyPerson[0] = "Charlie"; // 错误
-
元组常用于返回多个值,如函数输出,或表示坐标、RGB 值等固定结构。
实际应用:数据列表处理场景
掌握这些概念后,让我们看看实际应用。例如,在处理用户列表或 API 数据时:
-
简单数据列表:
typescriptinterface User { id: number; name: string; } let users: User[] = [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]; let names: string[] = users.map(u => u.name); // ["Alice", "Bob"] -
配置常量 :
使用 readonly 数组存储不可变选项。
typescriptconst options: readonly string[] = ["low", "medium", "high"]; function setLevel(level: typeof options[number]) { // 限制输入为选项之一 // 实现 } setLevel("medium"); // 有效 // setLevel("extreme"); // 错误 -
元组在函数中 :
返回多值结果。
typescriptfunction getStats(scores: number[]): [number, number] { // [平均, 最高] let avg = scores.reduce((a, b) => a + b) / scores.length; let max = Math.max(...scores); return [avg, max]; } let [average, highest] = getStats([80, 90, 70]); // average: number, highest: number
在 web 开发中,数组用于状态管理(如 React 的 useState),元组则处理 CSV 解析或键值对。readonly 则在 Redux 等库中防止状态突变。
这些工具在大型项目中能显著减少 bug,例如在数据校验时,确保列表不被意外修改。
结语:扩展集合处理的视野
通过本篇文章,您已了解数组、元组及其注解的精髓,以及 readonly 的保护作用。这些知识将为您处理复杂数据铺平道路。建议在您的项目中实践,例如构建一个简单的 todo 列表。下一期将探讨 any、unknown 和 void 等特殊类型,敬请关注。若有疑问,欢迎讨论。我们将继续深化 TypeScript 的探索。