枚举的遍历键给出了打字问题

traverse keys of enum gives typing issue

假设您要打印枚举的所有值

enum AnEnum {
    a = 'a',
    b = 'b'
}

const keys = Object.keys(AnEnum);

keys.forEach(key => {  
     console.log(AnEnum[key]);
});

这会产生以下错误

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'typeof AnEnum'. No index signature with a parameter of type 'string' was found on type 'typeof AnEnum'

DEMO

我只能通过添加 any

来解决这个问题
(AnEnum as any)[key]

但我想应该有更好的解决方案。有什么建议吗?

The Object.keys() method is given a typing in the TypeScript standard library 像这样:

interface ObjectConstructor {
  keys(o: object): string[];
}

return 类型是 string[]。这意味着 Object.keys(obj)Array<string> 类型的值,而 不是 类型 Array<keyof typeof obj> 的值(其中 the keyof operator represents a union of the known keys of an object type). See 是对为什么。这里我只想说编译器不能保证一个对象只有它知道的键。

这意味着如果您尝试使用仅已知为 string 的键对对象进行索引,则只有在已知该对象具有 string [=29= 时才有效] 和编译器警告。


在这种情况下,您确定您的对象只有已知键(例如,string enum where there's no reverse mapping), you can use a type assertion 告诉编译器:

const keys = Object.keys(AnEnum) as Array<keyof typeof AnEnum>;

然后你的循环就会工作:

keys.forEach(key => {
    console.log(AnEnum[key]); // okay
});

请注意 Object.keys(obj) as Array<keyof typeof obj> 不是万灵药。如果事实证明 obj 确实有比编译器知道的更多的键,更糟糕的是,这些键的 属性 值与已知键的值不是同一类型,那么你可以写编译正常但在运行时爆炸的东西:

interface Foo {
    a: string,
    b: string
}
const f = { a: "hello", b: "goodbye", c: 123 };
const foo: Foo = f; // okay, f is a valid Foo

(Object.keys(foo) as Array<keyof Foo>).forEach(k => console.log(foo[k].toUpperCase()));
// HELLO
// GOODBYE
//  RUNTIME ERROR! foo[k].toUpperCase is not a function

所以要小心!

Playground link to code