Index Signature是描述对象类型的机制,这些对象的键提前未知(或者可以动态添加),而值对应于特定类型。它允许创建字典对象(map/dictionary),其中属性列表在编译时未知。
背景:在JavaScript中,对象常常充当关联数组。TypeScript的静态类型要求指定键和值的类型。Index Signature解决了主要问题:描述对象,其中键不是严格编写的属性,而是字符串(或数字),值是特定类型。
问题:在处理这些对象时,可能会遇到已知属性与index signature冲突的情况,或者失去关于特定属性的信息。关于继承类型及字典结构扩展还有一些细微之处。
解决方案:Index Signature用于描述动态属性,通常键为string或number类型,例如用于集合、缓存对象或API响应,形式为{ [key: string]: T }。为了保持类型控制,必须同时描述固定属性和index signature,或者如果需要,则构成union类型。
代码示例:
interface StringNumberMap { [key: string]: number; } const map: StringNumberMap = { apples: 2, oranges: 5, bananas: 3 };
关键特性:
如果在带有index signature的接口中添加与类型不兼容的固定属性会发生什么?
如果属性类型与index signature中指定的类型不兼容,TypeScript会报错。
interface BadDict { [key: string]: number; error: string; // 错误:string与number不兼容 }
是否可以同时声明多个具有不同键类型(number和string)的index signature?
可以,但有个注意事项:在TypeScript中,number类型的键会自动转换为字符串。带有number的index signature仅仅是string键的同义词。
interface NumStrDict { [key: string]: number; [key: number]: number; }
可以在index signature的值中使用union类型或接口吗?
可以,值可以是union类型或接口。这样可以描述复杂对象的字典。
interface Dict { [key: string]: string | number; }
在API响应的接口中使用了[key: string]: any。后来的返回对象包含不同结构的数据,导致运行时错误并增加了代码维护的困难。
优点:
缺点:
描述了缓存对象的接口,其中值是严格定义的类型(例如,UserData),并注释键是userId(string):
interface UserCache { [userId: string]: UserData; }
优点:
缺点: