在 TypeScript 中,数组主要通过两种方式进行描述:类型[] 和 Array<类型>。对于具有不同类型元素的数组,使用联合类型 (union types) 或元组 (tuples),后者可以描述固定数量的不同类型的元素。
数组声明:
let numbers: number[] = [1, 2, 3]; let strings: Array<string> = ['a', 'b', 'c'];
具有不同类型元素的数组:
let mixed: (string | number)[] = [1, 'a', 2];
元组 (tuples):
let tuple: [string, number, boolean] = ['hello', 42, true];
当预期结构是固定的(例如,函数返回多个不同类型的值时)时,使用元组更方便,而数组则适用于元素数量和类型可以混合或不确定的情况。
在定义长度为 N 的元组之后,是否可以通过 push 方法向其添加元素?这对类型系统有什么影响?
答案: 是的,可以向元组中推送元素——编译器允许这样做,尽管这违反了元组长度的有限性假设。新元素的类型将被转换为元组中所有可能类型的联合:
let tuple: [number, string] = [42, 'foo']; tuple.push(true); // OK! 现在的元组: [number, string, boolean],但类型没有更新,没有错误! console.log(tuple); // [42, 'foo', true]
因此,需要手动控制对元组的操作和它们的可变性,或者将它们设置为只读。
故事
开发者描述了一个返回元组 [number, string] 的函数,但后来开始通过 push 向结果中添加元素。这导致了类型的不匹配:后续代码期待正好两个特定类型的元素,但得到了一个可变长度的数组,因而在解包值和访问不存在的索引时产生了运行时错误。
故事
为存储不同类型值的数组使用了 any[] 数组,认为这是一种通用解决方案。结果 TypeScript 停止检查类型的正确性,应用程序逻辑由于类型错误的转换开始出错,这些转换并未引发编译错误。
故事
在项目中,数组要么通过类型[] 要么通过 Array<类型> 进行描述——但在某些地方允许使用 let arr: any[](以便可以处理任何内容)。因此出现了无法控制的转换,任何数组都会接受这个函数,导致在尝试对不同类型元素调用不正确的方法时出现运行时错误。