0

我有一个从 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是 typestring而不是 type 'prop1' | 'prop2'。但我不明白为什么迭代器没有得到这种类型,因为我明确地迭代了myobject. 我是否错过了启用此行为的 tsconfig 属性?我不想这样做:

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

因为:

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

3 回答 3

7

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

1.类型断言

类型断言将强制key类型缩小到myobject键:

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

操场

2.明确声明关键变量

key 变量不能在 for-in 循环内输入,我们可以在外面声明它:

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

操场

3. 泛型

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

foo(myobject)

操场

为什么这是必要的?

key在一个for...in循环中,默认为 typestring。这是由于 TypeScript 的结构类型系统:确切的属性键形状仅在运行时知道,编译器无法静态分析,在编译时对象上存在哪些属性。key缩小到属性的类型myobject会使for...in循环在类型方面成为不安全的操作。

更多信息

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

我对这个有疑问。在for (var k in x)where xis of some type中,只有当 is 的确切类型时才T可以安全地说kis of type 。如果实际类型 of是 的子类型,正如我们的赋值兼容性规则所允许的那样,您将看到其中的值不是 type 。keyof TxTxTkkeyof T

于 2019-12-08T11:17:06.800 回答
5

A better way to this is:

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

In this way, it won't break when you add a property or rename it

于 2019-12-08T10:03:51.297 回答
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}`)
     });
  }
}
于 2019-12-08T09:51:29.613 回答