【问题标题】:Typescript element implicitly has type any with for...in loopsTypescript 元素隐式地具有任何类型,带有 for...in 循环
【发布时间】:2020-04-01 16:13:49
【问题描述】:

我有一个从 JSON 文件(带有resolveJsonModule: true)导入的 JSON 对象。 对象如下所示:

"myobject": {
  "prop1": "foo",
  "prop2": "bar"
}

它的类型因此看起来像这样:

myobject: { prop1: string, prop2: string }

这很好,但是当我尝试使用 for...in 循环时,

for (const key in myobject)  {
  console.log(myobject[key])
}

我收到此错误:

TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ "prop1": string; "prop2": string; }'.
  No index signature with a parameter of type 'string' was found on type '{ "prop1": string; "prop2": string; }'.

我了解这意味着迭代器 key 的类型为 string 而不是 'prop1' | 'prop2' 类型。但我不明白为什么迭代器没有得到这种类型,因为我明确地迭代了myobject 的属性名称。我是否错过了启用此行为的 tsconfig 属性? 我不想这样做:

for (const key in myobject)  {
  console.log(myobject[key as 'prop1' | 'prop2'])
}

因为:

  1. 将来我可能会添加新的属性;和
  2. 这似乎有点作弊,我觉得有更好的方法来做到这一点。

【问题讨论】:

  • 由于这是一项您无法通过 for 循环访问它的项目,只需使用 myobject.prop1 获取价值

标签: typescript for-in-loop object-property


【解决方案1】:

更好的方法是:

for (const key in myobject)  {
  console.log(myobject[key as keyof typeof myobject])
}

这样,当你添加属性或重命名它时它不会中断

【讨论】:

    【解决方案2】:

    输入for...in循环的三种解决方案,我知道:

    1。类型断言

    type assertion 将强制将 key 类型缩小为 myobject 键:

    for (const key in myobject)  {
      console.log(myobject[key as keyof typeof myobject])
    }
    

    Playground

    2。显式声明关键变量

    关键变量cannot be typed在for-in循环里面,我们可以在外面声明它:

    let key: keyof typeof myobject // add this declaration
    for (key in myobject)  {
      console.log(myobject[key]) // works
    }
    

    Playground

    3。泛型

    function foo<T>(t: T) {
      for (const k in t) {
        console.log(t[k]) // works
      }
    }
    
    foo(myobject)
    

    Playground

    为什么需要这样做?

    keyfor...in 循环中将设计为default to type string。这是由于 TypeScript 的structural type system:确切的属性键形状仅在运行时知道,编译器无法静态分析,在编译时对象上存在哪些属性。将key 类型缩小为myobject 属性会使for...in 循环在类型方面成为不安全的操作。

    更多信息

    注意:一些链接资源讨论了Object.keys,同样的论点也成立。

    我对此表示怀疑。在for (var k in x) 中,其中x 属于某种类型T,只有当x 的确切类型是T 时,才能说k 属于keyof T 类型。如果x 的实际类型是T 的子类型,在我们的赋值兼容性规则允许的范围内,您将在k 中看到不属于keyof T 类型的值。

    【讨论】:

      【解决方案3】:

      如果您希望将来有一个动态对象,请创建一个这样的模型

      interface PropertyItemModel {
        propName: string;
        propValue: string;
      }
      

      在组件中可以循环获取数据

      export class AppComponent {
      
        items: PropertyItemModel[] = [];
      
        constructor() {
      
          this.items = [
            { propName: "1", propValue: "foo" },
            { propName: "2", propValue: "bar" }]
      
           this.items.forEach(item => {
              console.log(`name: ${item.propName} - value: ${item.propValue}`)
           });
        }
      }
      

      【讨论】:

      • 我明白你的意思,但我不想重建依赖于这个键值对象的整个基础架构 :) 我可能会在未来的项目中使用它
      猜你喜欢
      • 2021-10-04
      • 2023-03-27
      • 2023-02-07
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      • 2019-01-06
      • 2021-10-27
      • 1970-01-01
      相关资源
      最近更新 更多