编程前端开发者

TypeScript 的索引签名(index signatures)机制是如何工作的?它用于什么,细节有哪些,在设计这样的结构时有哪些风险?

用 Hintsage AI 助手通过面试

答案。

问题历史

TypeScript 允许描述具有动态属性名称的对象,当无法预先确定所有键时,可以使用索引签名,这是为了类型化变体对象(映射、外部服务器的数据等)的方式。

问题

没有索引签名的对象只能基于预先定义的键进行解释,任何其他键都会导致编译错误。同时,错误的签名声明可能会模糊对象所有属性的类型,降低类型的严格性并导致错误。

解决方案

只有在合理的情况下明确声明索引签名。对于通过字符串键对对象数组进行类型化,请使用以下形式:

示例代码:

interface Dictionary { [key: string]: number; length?: number; } const sample: Dictionary = { apples: 4, oranges: 10 }; sample['bananas'] = 6;

关键特点:

  • 允许描述具有任意键的集合
  • 基于所有元素的统一值类型
  • 由于签名,所有附加属性必须符合该类型

带有陷阱的问题。

是否可以为索引签名中的不同键指定不同的值类型?

不可以,类型在所有键集上是统一的,如果您指定 [key: string]: number,那么 sample.length 也必须是 number:这在将索引签名与已知属性一起使用时常常会导致错误。

是否可以使用符号(symbol)来创建索引签名?

可以,从 ES6 开始,TypeScript 支持基于符号的索引签名:

interface SymbolMap { [key: symbol]: string; }

如果声明一个带有索引签名和其他不同类型属性的对象,会发生什么?

如果属性的类型与索引签名所声明的值类型不兼容,编译器将显示错误。可以通过使用联合类型或将这些字段分离到单独的接口中来解决此问题。

常见类型错误和反模式

  • 过度使用索引签名而不是严格的接口
  • 对象类型模糊
  • 错误地组合已知属性和索引属性

生活中的示例

负面案例

对于服务器的任何响应,使用接口 {[key: string]: any},这导致由于失去对数据结构的控制而产生的潜在错误。

优点:

  • 通用性

缺点:

  • 完全失去对象内部的严格类型
  • 隐藏的错误,生产环境中的“惊喜”

正面案例

严格用于字典的索引签名(例如,基于键的配置),而已知属性只有在它们的类型在签名外部声明时才使用。

优点:

  • 为集合/映射提供明确的结构
  • 对于已知字段保持严格的类型

缺点:

  • 需要更多时间来设计正确的对象架构