Typescript 元素隐式具有类型 any 和 for...in 循环

Typescript element implicitly has type any with for...in loops

我有一个从 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; }'.

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

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

因为:

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

如果你想让一个对象在未来是动态的,创建一个像这样的模型

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}`)
     });
  }
}

更好的方法是:

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

这样,添加属性或重命名

时不会中断

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

1。类型断言

A 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 循环中将由 TypeScript 设计 default to type string. This is due to the structural type system:确切属性的键形状仅在 运行 时已知,编译器无法静态分析编译时对象上存在哪些属性。 key 类型缩小为 myobject 属性会使 for...in 循环成为类型不安全的操作。

更多信息

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

I have my doubts about this one. In for (var k in x) where x is of some type T, it is only safe to say that k is of type keyof T when the exact type of x is T. If the actual type of x is a subtype of T, as is permitted by our assignment compatibility rules, you will see values in k that are not of type keyof T.