我在TypeScript中定义了以下enum:

enum Color{
    Red, Green
}

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

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

如何将该值转换为enum?


当前回答

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;

其他回答

如果你正在处理TypeScript 4.1+和字符串enum,并且你想要一个简单的具有编译时和运行时安全的字符串到enum转换器,下面的工作很好:

export const asEnum = <
  T extends { [key: string]: string },
  K extends keyof T & string
>(
  enumObject: T,
  value: `${T[K]}`
): T[K] => {
  if (Object.values(enumObject).includes(value)) {
    return (value as unknown) as T[K];
  } else {
    throw new Error('Value provided was not found in Enum');
  }
};

enum Test {
  hey = 'HEY',
}

const test1 = asEnum(Test, 'HEY');   // no complaints here
const test2 = asEnum(Test, 'HE');    // compile-time error
const test3 = asEnum(Test, 'HE' as any); // run-time error

我正在寻找一个答案,可以从字符串中获得enum,但在我的情况下,enum值有不同的字符串值对应。OP有一个简单的枚举颜色,但我有一些不同的东西:

enum Gender {
  Male = 'Male',
  Female = 'Female',
  Other = 'Other',
  CantTell = "Can't tell"
}

当你试图解决性别问题时。CantTell与"Can't tell"字符串,它返回未定义的原始答案。

另一个答案

基本上,受到这个答案的强烈启发,我想出了另一个答案:

export const stringToEnumValue = <ET, T>(enumObj: ET, str: string): T =>
  (enumObj as any)[Object.keys(enumObj).filter(k => (enumObj as any)[k] === str)[0]];

笔记

我们使用筛选器的第一个结果,假设客户端从枚举中传递一个有效的字符串。如果不是这样,则返回undefined。 我们将enumObj转换为any,因为在TypeScript 3.0+(目前使用TypeScript 3.5)中,enumObj被解析为unknown。

使用实例

const cantTellStr = "Can't tell";

const cantTellEnumValue = stringToEnumValue<typeof Gender, Gender>(Gender, cantTellStr);
console.log(cantTellEnumValue); // Can't tell

注意:而且,正如有人在评论中指出的那样,我还想使用noImplicitAny。

更新版本

没有对任何正确类型的强制转换。

export const stringToEnumValue = <T, 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];

此外,更新版本有一个更简单的方法来调用它,更可读:

stringToEnumValue(Gender, "Can't tell");

对于Typescript >= 4,此代码工作:

enum Color{
    Red, Green
}

// Conversion :
var green= "Green";
var color : Color = green as unknown as Color; 

我需要知道如何循环枚举值(正在测试许多排列的几个enum),我发现这工作得很好:

export enum Environment {
    Prod = "http://asdf.com",
    Stage = "http://asdf1234.com",
    Test = "http://asdfasdf.example.com"
}

Object.keys(Environment).forEach((environmentKeyValue) => {
    const env = Environment[environmentKeyValue as keyof typeof Environment]
    // env is now equivalent to Environment.Prod, Environment.Stage, or Environment.Test
}

来源:https://blog.mikeski.net/development/javascript/typescript-enums-to-from-string/

TypeScript 0.9中的枚举是基于字符串+数字的。简单转换不需要类型断言:

enum Color{
    Red, Green
}

// To String
 var green: string = Color[Color.Green];

// To Enum / number
var color : Color = Color[green];

在网上试试

我在我的OSS书籍https://basarat.gitbook.io/typescript/type-system/enums中有关于这个和其他Enum模式的文档