我在TypeScript中定义了以下enum:

enum Color{
    Red, Green
}

现在在我的函数中,我以字符串的形式接收颜色。我尝试了以下代码:

var green= "Green";
var color : Color = <Color>green; // Error: can't convert string to enum

如何将该值转换为enum?


当前回答

这些答案对我来说都太复杂了……

您可以简单地在枚举上创建一个解析函数,期望其中一个键作为参数。添加新颜色时,不需要进行其他更改

enum Color { red, green}

// Get the keys 'red' | 'green' (but not 'parse')
type ColorKey = keyof Omit<typeof Color, 'parse'>;

namespace Color {
  export function parse(colorName: ColorKey ) {
    return Color[colorName];
  }
}

// The key 'red' exists as an enum so no warning is given
Color.parse('red');  // == Colors.red

// Without the 'any' cast you would get a compile-time warning
// Because 'foo' is not one of the keys in the enum
Color.parse('foo' as any); // == undefined

// Creates warning:
// "Argument of type '"bar"' is not assignable to parameter of type '"red" | "green"'"
Color.parse('bar');

其他回答

TL;博士: :

创建一个函数,解析字符串值并将其转换为枚举。 如果你需要给定值的键名,不要使用TS enum。

首先,枚举是人类可读的名称和值之间的映射,这就是它的用途。

默认值: TS默认情况下会确保枚举中定义的键有唯一的值。

This

enum Color {
    Red, Green
}

等于

enum Color {
    Red = 0,
    Green = 1
}

转译的js代码都将

"use strict";
var Color;
(function (Color) {
    Color[Color["Red"] = 0] = "Red";
    Color[Color["Green"] = 1] = "Green";
})(Color || (Color = {}));

由于这是不可读的,下面是一旦创建的结果对象:

{0: 'Red', 1: 'Green', Red: 0, Green: 1}

该对象具有字符串和数字属性(不可能有任何冲突,因为您不能将枚举键定义为数字)。TS足够酷,可以生成一个包含映射键->值和值->键的对象。

感谢上帝,这是一个双射映射,即每个唯一值都有它的唯一键(因此反过来也是正确的)

现在麻烦来了,如果我强制使用相同的值呢?

enum Color {
    Red = 0,
    Green = 0
}

这是最终创建的js对象

{0: 'Green', Red: 0, Green: 0}

我们不再有双射,(这是满射),没有魔法映射0:['Green', 'Red']。只有0:“绿色”,我们失去了0:“红色”

提示:当值为数字时,TS将总是尝试放置反向映射(value ->键)。

现在,正如你所知道的,你也可以在枚举中定义字符串值,让我们只将Green值更改为"Green"

enum Color {
    Red = 0,
    Green = "GREEN"
}

这是生成的js对象

{0: 'Red', Red: 0, Green: 'GREEN'}

如你所见,Typescript并没有生成映射值->键。 它不会,因为您可能会在值和键名之间发生冲突。记住:键不能是数字,因此当值是数字时,就没有碰撞的风险。

这使您明白,您不应该依赖于枚举的value ->键映射。映射可能根本不存在或不准确。

同样,枚举是(也只能被视为)人类可读的值名称。在某些情况下,ts甚至根本不会产生任何反向映射。这就是定义枚举const时的情况。

const枚举是一个纯编译时的枚举,TS会在编译时将枚举的使用替换为其对应的值

例如:

const enum Color {
    Red = 0,
    Green = "GREEN"
}

被转译为

"use strict";

所以我想说,没什么,因为“use strict”;跟我们写的都没有关系。

下面是一个用法的相同示例:

const enum Color {
    Red = 0,
    Green = "GREEN"
}
console.log(Color.Green);

被转译为

"use strict";
console.log("GREEN" /* Green */);

如你所见,颜色。Green被转译器替换为“Green”。

回到最初的问题,如何将字符串转换为enum ?

解析器解决方案: 我很抱歉,但我推荐的唯一干净的方法是写一个函数,使用开关情况是一个聪明的方法来实现这一点。

function parseColorName(color: string): Color {
  switch (color) {
    case 'Red': return Color.Red;
    case 'Green': return Color.Green;
    default: throw new Error('unknown color');
  }
}

自定义enum解决方案:

请注意,TS枚举是不透明的,这意味着编译器无法正确地键入值。出于这个原因(特别是当你需要使用反向映射时),我建议你自己做枚举,如下所示:

export const ColorType = {
  RED: 'Red',
  GREEN: 'Green',
} as const;

export type ColorType = typeof ColorType[keyof typeof ColorType];

下面是安全的(颜色只能取一个有效的已知值)。简而言之,您依赖于字符串联合而不是枚举值。

const color: ColorType= "Green";
// And if you need to create a color from the enum like value:
const anotherColor: ColorType = ColorType.RED;

如果您为枚举提供字符串值,则直接强制转换可以很好地工作。

enum Color {
  Green = "Green",
  Red = "Red"
}

const color = "Green";
const colorEnum = color as Color;

试试这个

var color: color =(任何颜色)["绿色];

这对于3.5.3版本来说很好

它在TypeScript 4.4.3 TS游乐场链接中为我工作。

  const stringToEnumValue = <T extends Record<string, string>, K extends keyof T>(
    enumObj: T,
    value: string,
  ): T[keyof T] | undefined =>
    enumObj[
      Object.keys(enumObj).filter(
        (k) => enumObj[k as K].toString() === value,
      )[0] as keyof typeof enumObj
    ];

  enum Color {
    Red = 'red',
    Green = 'green',
  }

  const result1 = stringToEnumValue(Color, 'yellow'); // undefined
  const result2 = stringToEnumValue(Color, 'green'); // Color.Green

  console.log(result1) // undefined = undefined
  console.log(result2) // Color.Green = "green"

枚举

enum MyEnum {
    First,
    Second,
    Three
}

示例使用

const parsed = Parser.parseEnum('FiRsT', MyEnum);
// parsed = MyEnum.First 

const parsedInvalid= Parser.parseEnum('other', MyEnum);
// parsedInvalid = undefined

忽略区分大小写的解析

class Parser {
    public static parseEnum<T>(value: string, enumType: T): T[keyof T] | undefined {
        if (!value) {
            return undefined;
        }

        for (const property in enumType) {
            const enumMember = enumType[property];
            if (typeof enumMember === 'string') {
                if (enumMember.toUpperCase() === value.toUpperCase()) {
                    const key = enumMember as string as keyof typeof enumType;
                    return enumType[key];
                }
            }
        }
        return undefined;
    }
}