首页 > 解决方案 > 打字稿:如何遍历由枚举值索引的对象

问题描述

我有一个这样声明的对象:

type MyType = { [key in MyEnum]?: number}

MyEnum 具有这种形式:

enum MyEnum {
  Foo = 1, Bar = 2
}

我想遍历我的对象键/值对,然后返回枚举值:

const myObject: MyType = {...}
for (const myKey in myObject) {
  // myKey is of type string, not "MyEnum". How to get back to it?
}

有没有办法做到这一点?

标签: typescriptfor-loopenums

解决方案


这个看似令人惊讶的问题是在 Typescript 中进行鸭式输入的结果,并且在较小程度上是对象在 Javascript 中的工作方式。

由于两个原因,将myKey其键入为字符串。首先,Typescript 不能保证一个对象只包含MyType. 鸭子类型允许您使用与请求MyType的位置具有相同和更多属性的对象。MyType这是 Typescript 的一个特性,但在这种情况下是一个障碍。

鸭子打字的例子

// Types
enum MyEnum {
  Foo = 1, Bar = 2
};

type MyType = { [key in MyEnum]?: number}

// Duck typing example
const normalObject: MyType = { [MyEnum.Foo]: 3, [MyEnum.Bar]: 4 };
const duckTypedObject = { [MyEnum.Foo]: 5, "extraProperty": 10};

function myFunction(obj: MyType){
  for (const myKey in obj) {
    console.log(myKey);
  }
}

myFunction(normalObject);
// This will print out "extraProperty" as well.
myFunction(duckTypedObject);

其次,因为 Javascript 中对象的属性只能是符号或字符串,所以其他类型被强制转换为字符串。由于 for 循环只会遍历对象的字符串属性,Typescript 选择string最具体的类型 for myKey

通常你仍然可以通过在构造myKey之外声明一个变量来输入。loop在这种情况下不起作用,因为您使用的是数字枚举。您需要解析字符串才能再次获取数字并将其转换回枚举。我强烈建议不要这样做。但是,您可以使用字符串枚举,但如果您的同事使用鸭子类型,这仍然会使您面临错误。

字符串枚举解决方案

enum MyStringEnum {
  Foo = "FOO", Bar = "BAR"
}

type MyType2 = { [key in MyStringEnum]?: number};
const obj: MyType2 = { [MyStringEnum.Foo]: 3};

let myKey: MyStringEnum;
for (const myKey in obj){
  console.log(myKey);
}

我的建议是使用MapTypescript 中的类型。正如您所看到的,在没有任何额外的黑客攻击的情况下键入了密钥,并且您回避了与鸭子键入有关的问题。

enum MyEnum {
  Foo = 1, Bar = 2
};

let myMap = new Map<MyEnum, number>([
  [MyEnum.Foo, 3],
  [MyEnum.Bar, 4]
]); 

for (const [key] of myMap){
  console.log(key);
}

这是可执行代码片段的链接。


推荐阅读