我想迭代一个TypeScript枚举对象,并获得每个枚举符号名称,例如: enum myEnum {entry1, entry2}

for (var entry in myEnum) { 
    // use entry's name here, e.g., "entry1"
}

当前回答

我看不正确的答案看累了,就自己做了。

这个有测试。 适用于所有类型的枚举。 正确地输入。

type EnumKeys<Enum> = Exclude<keyof Enum, number>

const enumObject = <Enum extends Record<string, number | string>>(e: Enum) => {
    const copy = {...e} as { [K in EnumKeys<Enum>]: Enum[K] };
    Object.values(e).forEach(value => typeof value === 'number' && delete copy[value]);
    return copy;
};

const enumKeys = <Enum extends Record<string, number | string>>(e: Enum) => {
    return Object.keys(enumObject(e)) as EnumKeys<Enum>[];
};

const enumValues = <Enum extends Record<string, number | string>>(e: Enum) => {
    return [...new Set(Object.values(enumObject(e)))] as Enum[EnumKeys<Enum>][];
};

enum Test1 { A = "C", B = "D"}
enum Test2 { A, B }
enum Test3 { A = 0, B = "C" }
enum Test4 { A = "0", B = "C" }
enum Test5 { undefined = "A" }
enum Test6 { A = "undefined" }
enum Test7 { A, B = "A" }
enum Test8 { A = "A", B = "A" }
enum Test9 { A = "B", B = "A" }

console.log(enumObject(Test1)); // {A: "C", B: "D"}
console.log(enumObject(Test2)); // {A: 0, B: 1}
console.log(enumObject(Test3)); // {A: 0, B: "C"}
console.log(enumObject(Test4)); // {A: "0", B: "C"}
console.log(enumObject(Test5)); // {undefined: "A"}
console.log(enumObject(Test6)); // {A: "undefined"}
console.log(enumObject(Test7)); // {A: 0,B: "A"}
console.log(enumObject(Test8)); // {A: "A", B: "A"}
console.log(enumObject(Test9)); // {A: "B", B: "A"}

console.log(enumKeys(Test1)); // ["A", "B"]
console.log(enumKeys(Test2)); // ["A", "B"]
console.log(enumKeys(Test3)); // ["A", "B"]
console.log(enumKeys(Test4)); // ["A", "B"]
console.log(enumKeys(Test5)); // ["undefined"]
console.log(enumKeys(Test6)); // ["A"]
console.log(enumKeys(Test7)); // ["A", "B"]
console.log(enumKeys(Test8)); // ["A", "B"]
console.log(enumKeys(Test9)); // ["A", "B"]

console.log(enumValues(Test1)); // ["C", "D"]
console.log(enumValues(Test2)); // [0, 1]
console.log(enumValues(Test3)); // [0, "C"]
console.log(enumValues(Test4)); // ["0", "C"]
console.log(enumValues(Test5)); // ["A"] 
console.log(enumValues(Test6)); // ["undefined"] 
console.log(enumValues(Test7)); // [0, "A"]
console.log(enumValues(Test8)); // ["A"]
console.log(enumValues(Test9)); // ["B", "A"]

在线版本。

其他回答

对我来说,一个更简单、实用和直接的方法来理解正在发生的事情,就是下面的列举:

enum colors { red, green, blue };

本质上将转换为:

var colors = { red: 0, green: 1, blue: 2,
               [0]: "red", [1]: "green", [2]: "blue" }

正因为如此,以下情况将是正确的:

colors.red === 0
colors[colors.red] === "red"
colors["red"] === 0

这创建了一个简单的方法来获取枚举的名称,如下所示:

var color: colors = colors.red;
console.log("The color selected is " + colors[color]);

它还创建了一种将字符串转换为枚举值的好方法。

var colorName: string = "green";
var color: colors = colors.red;
if (colorName in colors) color = colors[colorName];

以上两种情况更为常见,因为通常您对特定值的名称和以通用方式序列化值更感兴趣。

在TypeScript中,一个enum在javascript中被编译成一个map(从键中获取值):

enum MyEnum {
  entry0,
  entry1,
}

console.log(MyEnum['entry0']); // 0
console.log(MyEnum['entry1']); // 1

它还创建了一个反向映射(从值中获取键):

console.log(MyEnum[0]); // 'entry0'
console.log(MyEnum[0]); // 'entry1'

所以你可以通过以下方式访问一个条目的名称:

console.log(MyEnum[MyEnum.entry0]); // 'entry0'
console.log(MyEnum[MyEnum.entry1]); // 'entry1'

但是,string enum在设计上没有反向映射(参见注释和pull request),因为这可能导致映射对象中的键和值之间的冲突。

enum MyEnum {
  entry0 = 'value0',
  entry1 = 'value1',
}

console.log(MyEnum['value0']); // undefined
console.log(MyEnum['value1']); // undefined

如果你想强制你的字符串enum编译一个反向映射(你必须确保所有的键和值都是不同的),你可以使用这个技巧:

enum MyEnum {
  entry0 = <any>'value0',
  entry1 = <any>'value1',
}

console.log(MyEnum['value0']); // 'entry0'
console.log(MyEnum['value1']); // 'entry1'
console.log(MyEnum[MyEnum.entry0]); // 'entry0'
console.log(MyEnum[MyEnum.entry1]); // 'entry1'

我卑微的2美分基于阅读一个了不起的评论从github TS讨论

const EnvironmentVariants = ['development', 'production', 'test'] as const 
type EPredefinedEnvironment = typeof EnvironmentVariants[number]

然后在编译时:

// TS2322: Type '"qaEnv"' is not assignable to type '"development" | "production" | "test"'.
const qaEnv: EPredefinedEnvironment = 'qa' 

在运行时:

function isPredefinedEnvironemt(env: string) {
  for (const predefined of EnvironmentVariants) {
    if (predefined === env) {
      return true
    }
  }
  return false
}

assert(isPredefinedEnvironemet('test'), true)
assert(isPredefinedEnvironemet('qa'), false)

注意,for(const index in environmentvariables){…}将遍历"0","1","2"集合

老问题了,为什么不使用const对象映射呢?

不要这样做:

enum Foo {
    BAR = 60,
    EVERYTHING_IS_TERRIBLE = 80
}

console.log(Object.keys(Foo))
// -> ["60", "80", "BAR", "EVERYTHING_IS_TERRIBLE"]
console.log(Object.values(Foo))
// -> ["BAR", "EVERYTHING_IS_TERRIBLE", 60, 80]

这样做(注意as const强制转换):

const Foo = {
    BAR: 60,
    EVERYTHING_IS_TERRIBLE: 80
} as const

console.log(Object.keys(Foo))
// -> ["BAR", "EVERYTHING_IS_TERRIBLE"]
console.log(Object.values(Foo))
// -> [60, 80]

我看不正确的答案看累了,就自己做了。

这个有测试。 适用于所有类型的枚举。 正确地输入。

type EnumKeys<Enum> = Exclude<keyof Enum, number>

const enumObject = <Enum extends Record<string, number | string>>(e: Enum) => {
    const copy = {...e} as { [K in EnumKeys<Enum>]: Enum[K] };
    Object.values(e).forEach(value => typeof value === 'number' && delete copy[value]);
    return copy;
};

const enumKeys = <Enum extends Record<string, number | string>>(e: Enum) => {
    return Object.keys(enumObject(e)) as EnumKeys<Enum>[];
};

const enumValues = <Enum extends Record<string, number | string>>(e: Enum) => {
    return [...new Set(Object.values(enumObject(e)))] as Enum[EnumKeys<Enum>][];
};

enum Test1 { A = "C", B = "D"}
enum Test2 { A, B }
enum Test3 { A = 0, B = "C" }
enum Test4 { A = "0", B = "C" }
enum Test5 { undefined = "A" }
enum Test6 { A = "undefined" }
enum Test7 { A, B = "A" }
enum Test8 { A = "A", B = "A" }
enum Test9 { A = "B", B = "A" }

console.log(enumObject(Test1)); // {A: "C", B: "D"}
console.log(enumObject(Test2)); // {A: 0, B: 1}
console.log(enumObject(Test3)); // {A: 0, B: "C"}
console.log(enumObject(Test4)); // {A: "0", B: "C"}
console.log(enumObject(Test5)); // {undefined: "A"}
console.log(enumObject(Test6)); // {A: "undefined"}
console.log(enumObject(Test7)); // {A: 0,B: "A"}
console.log(enumObject(Test8)); // {A: "A", B: "A"}
console.log(enumObject(Test9)); // {A: "B", B: "A"}

console.log(enumKeys(Test1)); // ["A", "B"]
console.log(enumKeys(Test2)); // ["A", "B"]
console.log(enumKeys(Test3)); // ["A", "B"]
console.log(enumKeys(Test4)); // ["A", "B"]
console.log(enumKeys(Test5)); // ["undefined"]
console.log(enumKeys(Test6)); // ["A"]
console.log(enumKeys(Test7)); // ["A", "B"]
console.log(enumKeys(Test8)); // ["A", "B"]
console.log(enumKeys(Test9)); // ["A", "B"]

console.log(enumValues(Test1)); // ["C", "D"]
console.log(enumValues(Test2)); // [0, 1]
console.log(enumValues(Test3)); // [0, "C"]
console.log(enumValues(Test4)); // ["0", "C"]
console.log(enumValues(Test5)); // ["A"] 
console.log(enumValues(Test6)); // ["undefined"] 
console.log(enumValues(Test7)); // [0, "A"]
console.log(enumValues(Test8)); // ["A"]
console.log(enumValues(Test9)); // ["B", "A"]

在线版本。