casting - TypeScript:类型中缺少索引签名

标签 casting 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
  }
})

最佳答案

问题是当推断出类型时,那么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 认为它是一个只有两个属性的普通对象,然后您稍后尝试将它用作字典,它会不高兴。

关于casting - TypeScript:类型中缺少索引签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37006008/

相关文章:

C# 在泛型类中调用方法

C++ 无法通过虚拟基 A 从基 A 转换为派生类型 B

javascript - ReferenceError : performance is not defined when using performance. 现在()

angularjs - 使用 Angular 2 Typescript 设置 http header

javascript - SlickGrid 多级分组与组级选择

javascript - 多个 TypeScript 文件配置

java - Java 父类(super class)数组中的子类

c - 类型转换为其中包含另一个结构 ptr 的结构

c++ - 为什么运算符的操作数需要是同一类型?

angular - 错误 : No Firebase App '[DEFAULT]' has been created