TypeScript:类型中缺少索引签名

新手上路,请多包涵

我希望 MyInterface.dic 像字典一样 name: value ,我将其定义如下:

 interface MyInterface {
    dic: { [name: string]: number }
}

现在我创建一个等待我的类型的函数:

 function foo(a: MyInterface) {
    ...
}

和输入:

 let o = {
    dic: {
        'a': 3,
        'b': 5
    }
}

我期待 foo(o) 是正确的,但编译器正在下降:

 foo(o) // TypeScript error: Index signature is missing in type { 'a': number, 'b': number }

我知道有一个可能的转换: let o: MyInterface = { ... } 这可以解决问题,但 为什么 TypeScript 无法识别我的类型?


额外:如果 o 被声明为内联,则工作正常:

 foo({
  dic: {
    'a': 3,
    'b': 5
  }
})

原文由 Manu Artero 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

问题是当推断类型时,那么 o 的类型是:

 { dic: { a: number, b: number } }

这与 { dic: { [name: string]: number } } 。至关重要的是,使用顶部签名您不能执行类似 o.dic['x'] = 1 的操作。有了第二个签名,你就是。

它们在运行时是等价的类型(实际上,它们的值完全相同),但是 TypeScript 的安全性很大一部分来自于它们不一样的事实,它只会让你将对象视为字典,如果它知道它明确地打算作为一个。这就是阻止您意外读取和写入对象上完全不存在的属性的原因。

解决方案是确保 TypeScript 知道它是用作字典的。这意味着:

  • 在某处显式提供一个类型,告诉它它是一个字典:

let o: MyInterface

  • 断言它是一个字典内联:

let o = { dic: <{ [name: string]: number }> { 'a': 1, 'b': 2 } }

  • 确保它是 TypeScript 为您推断的初始类型:

foo({ dic: { 'a': 1, 'b': 2 } })

如果有一种情况,TypeScript 认为它是一个只有两个属性的普通对象,然后你稍后尝试将它用作字典,它会不高兴。

原文由 Tim Perry 发布,翻译遵循 CC BY-SA 3.0 许可协议

在我的情况下,只需要使用 type 而不是 interface

原文由 Jöcker 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进