如何在TypeScript中将字符串转换为枚举?

Ami*_*abh 247 typescript

我在TypeScript中定义了以下枚举?

enum Color{
    Red, Green
}
Run Code Online (Sandbox Code Playgroud)

现在在我的函数中,我收到颜色作为字符串.我试过以下代码:

var green= "Green";
var color : Color = <Color>green; // Error: can't convert string to enum
Run Code Online (Sandbox Code Playgroud)

如何将该值转换为枚举?

bas*_*rat 353

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

enum Color{
    Red, Green
}

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

// To Enum / number
var color : Color = Color[green];
Run Code Online (Sandbox Code Playgroud)

在线尝试

我在OSS书中有关于此和其他Enum模式的文档:https://basarat.gitbooks.io/typescript/content/docs/enums.html

  • 这不适用于`--noImplicitAny`(在VS中未选中"允许隐式'任何'类型").它产生`错误TS7017:对象类型的索引签名隐式具有'任何'类型.对我来说这工作:`var color:Color =(<any> Color)[green];`(用1.4版测试) (76认同)
  • @Naxos84 看我的答案 /sf/answers/3925330391/ (5认同)
  • 如果--noImplicitAny`var color:Color = Color [绿色为color类型的键],请确保使用此选项。 (4认同)
  • @Jonas您能否解释或提供文档为什么/您的解决方案如何工作? (4认同)
  • @Vojta说的没错.它不适用于VS 2012.这个工作但颜色变化:颜色=(<任意>颜色)[绿色]; (2认同)
  • 它在这里也不起作用,官方文档似乎证实了这一点:https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html#string-enums (2认同)

Vic*_*tor 95

从Typescript 2.1开始,枚举中的字符串键是强类型的.keyof typeof用于获取有关可用字符串键的信息(1):

enum Color{
    Red, Green
}

let typedColor: Color = Color.Green;
let typedColorString: keyof typeof Color = "Green";

// Error "Black is not assignable ..." (indexing using Color["Black"] will return undefined runtime)
typedColorString = "Black";

// Error "Type 'string' is not assignable ..." (indexing works runtime)
let letColorString = "Red";
typedColorString = letColorString;

// Works fine
typedColorString = "Red";

// Works fine
const constColorString = "Red";
typedColorString = constColorString

// Works fine (thanks @SergeyT)
let letColorString = "Red";
typedColorString = letColorString as keyof typeof Color;

typedColor = Color[typedColorString];
Run Code Online (Sandbox Code Playgroud)

https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types

  • 一行答案:`const color: Color = Color[colorString as keyof typeof Color];` (9认同)
  • 所以我们可以使用类型转换:`let s ="Green"; 让typedColor = <keyof typeof Color> s;` (4认同)
  • `typedColorString = Color["Black"];` 现在返回 `错误 TS7015:元素隐式具有 'any' 类型,因为索引表达式不是 'number' 类型` (4认同)

ale*_*nia 72

如果您为枚举提供字符串值,则直接转换就可以了。

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

const color = "Green";
const colorEnum = color as Color;
Run Code Online (Sandbox Code Playgroud)

  • 这可能会产生误导,因为它不能防止无效颜色。`const colorEnum = "Blue" as Color` 不会出错,并且您会认为 `colorEnum` 没问题。但如果你要“console.log”它,你会看到“蓝色”。[Artru 的答案](/sf/answers/2908390901/) 很好,因为 `colorEnum` 将是 `undefined` - 然后您可以具体检查。 (11认同)
  • 将此与“Object.values(Enum).indexOf(value) &gt;= 0”检查配对,以查看它是否是有效值。 (6认同)

Nic*_* N. 44

如果您使用打字稿:上面的许多解决方案可能不起作用或过于复杂。

情况:字符串与枚举值不同(大小写不同)

enum Color {
  Green = "green",
  Red = "red"
}
Run Code Online (Sandbox Code Playgroud)

只需使用:

const color = "green" as Color
Run Code Online (Sandbox Code Playgroud)

请注意,这并不能保证枚举有效。

  • 我想使用枚举的原因之一是限制有效的情况。在此示例中,我可以执行“const color = 'banana' as Color”,它仍然可以正常解析,但颜色不再有效。 (12认同)

Art*_*tru 27

如果您确定输入字符串与Color enum完全匹配,则使用:

const color: Color = (<any>Color)["Red"];
Run Code Online (Sandbox Code Playgroud)

在输入字符串可能与Enum不匹配的情况下使用:

const mayBeColor: Color | undefined = (<any>Color)["WrongInput"];
if (mayBeColor !== undefined){
     // TypeScript will understand that mayBeColor is of type Color here
}
Run Code Online (Sandbox Code Playgroud)

操场


如果我们不转换enum<any>类型,则tsc将显示错误

元素隐式具有"任何"类型,因为索引表达式不是"数字"类型.

这意味着默认TS Enum类型使用数字索引,即 let c = Color[0]不使用字符串索引let c = Color["string"].这是Microsoft团队对更一般的问题对象字符串索引的已知限制.


Sly*_*nal 26

本说明涉及巴萨拉特的答案,而不是原始问题.

我在我自己的项目中遇到了一个奇怪的问题,即编译器使用相当于此代码的大小相当于"无法将字符串转换为颜色"的错误:

var colorId = myOtherObject.colorId; // value "Green";
var color: Color = <Color>Color[colorId]; // TSC error here: Cannot convert string to Color.
Run Code Online (Sandbox Code Playgroud)

我发现编译器类型推理变得混乱,它认为这colorId是一个枚举值而不是ID.要解决这个问题,我必须将ID转换为字符串:

var colorId = <string>myOtherObject.colorId; // Force string value here
var color: Color = Color[colorId]; // Fixes lookup here.
Run Code Online (Sandbox Code Playgroud)

我不确定是什么原因引起了这个问题,但我会在这里留下这个说明以防万一我遇到同样的问题.


Ami*_*abh 22

使用以下代码使其工作.

var green= "Green";
var color : Color= <Color>Color[green];
Run Code Online (Sandbox Code Playgroud)


小智 14

我也遇到了相同的编译器错误.只是Sly_cardinal方法的略微变化.

var color: Color = Color[<string>colorId];
Run Code Online (Sandbox Code Playgroud)


Jon*_*nas 14

enum Color{
    Red, Green
}

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

// To Enum / number
var color : Color = Color[green as keyof typeof Color]; //Works with --noImplicitAny
Run Code Online (Sandbox Code Playgroud)

此示例可--noImplicitAny在TypeScript中使用

来源:
https : //github.com/Microsoft/TypeScript/issues/13775#issuecomment-276381229 https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types

  • @Robin-Hoodie 有点晚了(但为了其他后来者的利益),但是 const 枚举完全从代码中编译出来,因此运行时代码没有对枚举键的引用,只有它们的文字值。因此它无法将这些值映射回枚举键。 (5认同)
  • 仅使无效值“未定义”的答案 (4认同)
  • 这是最好的答案! (3认同)

for*_*d04 13

最简单的方法

enum Color { Red, Green }

const c1 = Color["Red"]
const redStr = "Red" // important: use `const`, not mutable `let`
const c2 = Color[redStr]
Run Code Online (Sandbox Code Playgroud)

这适用于数字字符串枚举。无需使用类型断言

未知的枚举字符串

简单、不安全的变体
const redStrWide: string = "Red" // wide, unspecific typed string
const c3 = Color[redStrWide as keyof typeof Color]
Run Code Online (Sandbox Code Playgroud) 带检查的安全变体
const isEnumName = <T>(str: string, _enum: T): str is Extract<keyof T, string> =>
    str in _enum
const enumFromName = <T>(name: string, _enum: T) => {
    if (!isEnumName(name, _enum)) throw Error() // here fail fast as an example
    return _enum[name]
}
const c4 = enumFromName(redStrWide, Color)
Run Code Online (Sandbox Code Playgroud)

转换字符串枚举值

字符串枚举没有反向映射(与数字枚举相反)。我们可以创建一个查找助手来将枚举值字符串转换为枚举类型:

enum ColorStr { Red = "red", Green = "green" }

const c5_by_name = ColorStr["Red"] // ? this works
const c5_by_value_error = ColorStr["red"] // ? , but this not

const enumFromValue = <T extends Record<string, string>>(val: string, _enum: T) => {
    const enumName = (Object.keys(_enum) as Array<keyof T>).find(k => _enum[k] === val)
    if (!enumName) throw Error() // here fail fast as an example
    return _enum[enumName]
}

const c5 = enumFromValue("red", ColorStr)
Run Code Online (Sandbox Code Playgroud)

游乐场示例


elb*_*aid 12

我正在寻找一个可以enum从 a 中得到 an 的答案string,但在我的例子中,枚举值具有不同的字符串值对应物。OP 有一个简单的 enum for Color,但我有一些不同的东西:

enum Gender {
  Male = 'Male',
  Female = 'Female',
  Other = 'Other',
  CantTell = "Can't tell"
}
Run Code Online (Sandbox Code Playgroud)

当您尝试Gender.CantTell使用"Can't tell"字符串解析时,它会返回undefined原始答案。

另一个答案

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

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

笔记

  • 我们采取的第一个结果filter,假设客户端从枚举传递一个有效的字符串。如果不是这种情况,undefined将被退回。
  • 我们转换enumObjany,因为使用 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
Run Code Online (Sandbox Code Playgroud)

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

更新后的版本

没有any强制转换和正确的打字。

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];
Run Code Online (Sandbox Code Playgroud)

此外,更新后的版本有更简单的调用方式,并且更具可读性:

stringToEnumValue(Gender, "Can't tell");
Run Code Online (Sandbox Code Playgroud)

  • ```类型 'T[K]' 上不存在属性 'toString'。ts(2339) ``` (6认同)

Fla*_*ken 10

长话短说:\n或者:

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

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

\n

默认值:\nTS 默认情况下将确保您为枚举的定义键拥有唯一的值。

\n

\n
enum Color {\n    Red, Green\n}\n
Run Code Online (Sandbox Code Playgroud)\n

相当于

\n
enum Color {\n    Red = 0,\n    Green = 1\n}\n
Run Code Online (Sandbox Code Playgroud)\n

两者的转译后的 js 代码将是

\n
"use strict";\nvar Color;\n(function (Color) {\n    Color[Color["Red"] = 0] = "Red";\n    Color[Color["Green"] = 1] = "Green";\n})(Color || (Color = {}));\n
Run Code Online (Sandbox Code Playgroud)\n

由于这是不可读的,因此创建后的结果对象如下:

\n
{0: \'Red\', 1: \'Green\', Red: 0, Green: 1}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

感谢上帝,这是一个双射映射,即每个唯一值都有它的唯一键(因此反之亦然)

\n

那么麻烦来了,如果我强制使用相同的值怎么办?

\n
enum Color {\n    Red = 0,\n    Green = 0\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这是创建的 js 对象的结果

\n
{0: \'Green\', Red: 0, Green: 0}\n
Run Code Online (Sandbox Code Playgroud)\n

我们不再有双射(这是surjectif),没有神奇的映射0 : [\'Green\', \'Red\']。只是0 : \'Green\'我们失去了0 : \'Red\'

\n

要点:当值是数字时,TS 总是会尝试放置反向映射(值 -> 键)。

\n

现在您可能知道,您还可以在枚举中定义字符串值,让我们仅将绿色值更改为“绿色”

\n
enum Color {\n    Red = 0,\n    Green = "GREEN"\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这是生成的 js 对象

\n
{0: \'Red\', Red: 0, Green: \'GREEN\'}\n
Run Code Online (Sandbox Code Playgroud)\n

正如您所看到的,Typescript 不会生成映射值 -> 键。\n它也不会生成,因为您最终可能会遇到值和键名称之间的冲突。请记住:键不能是数字,因此当值是数字时,不存在冲突的风险。

\n

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

\n

同样,枚举是且仅应被视为人类可读的值名称。在某些情况下,ts 甚至根本不会生成任何反向映射。当您定义枚举常量时就是这种情况。

\n

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

\n

例如:

\n
const enum Color {\n    Red = 0,\n    Green = "GREEN"\n}\n
Run Code Online (Sandbox Code Playgroud)\n

被转译为

\n
"use strict";\n
Run Code Online (Sandbox Code Playgroud)\n

所以只是说 \xe2\x80\xa6 没什么,因为“使用严格”;甚至与我们写的内容无关。

\n

这是相同的示例及其用法:

\n
const enum Color {\n    Red = 0,\n    Green = "GREEN"\n}\nconsole.log(Color.Green);\n
Run Code Online (Sandbox Code Playgroud)\n

被转译为

\n
"use strict";\nconsole.log("GREEN" /* Green */);\n
Run Code Online (Sandbox Code Playgroud)\n

正如您所看到的,Color.Green 被转译器替换为“GREEN”。

\n

那么回到最初的问题,如何将字符串转换为枚举?

\n

解析器解决方案: \n我很抱歉,但我推荐的唯一干净的方法是编写一个函数,使用 switch case 是实现此目的的聪明方法。

\n
function parseColorName(color: string): Color {\n  switch (color) {\n    case \'Red\': return Color.Red;\n    case \'Green\': return Color.Green;\n    default: throw new Error(\'unknown color\');\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

自定义枚举解决方案:

\n

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

\n
export const ColorType = {\n  RED: \'Red\',\n  GREEN: \'Green\',\n} as const;\n\nexport type ColorType = typeof ColorType[keyof typeof ColorType];\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
const color: ColorType= "Green";\n// And if you need to create a color from the enum like value:\nconst anotherColor: ColorType = ColorType.RED;\n
Run Code Online (Sandbox Code Playgroud)\n


Luk*_*uka 9

如果typescript编译器知道变量的类型是字符串而不是这个

let colorName : string = "Green";
let color : Color = Color[colorName];
Run Code Online (Sandbox Code Playgroud)

否则你应该显式地将其转换为字符串(以避免编译器警告)

let colorName : any = "Green";
let color : Color = Color["" + colorName];
Run Code Online (Sandbox Code Playgroud)

在运行时,两种解决方案都可以

  • 为什么不使用类型转换`<string> colorName`而不是`""+ colorName`? (3认同)

Saf*_*eli 9

几乎所有答案都使用不安全的强制转换(asis)。这个没有:


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

const colorsMap = new Map<string,Color>(Object.values(Color).map((v) => [v,v]))

function parseColor(volumeData: string): Color | undefined {
    return colorsMap.get(volumeData)
}

const color = parseColor("red")
Run Code Online (Sandbox Code Playgroud)


mik*_*keb 8

我需要知道如何遍历枚举值(正在测试多个枚举的大量排列),我发现这很有效:

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
}
Run Code Online (Sandbox Code Playgroud)

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


小智 7

对于 TS 3.9.x

var color : Color = Color[green as unknown as keyof typeof Color];
Run Code Online (Sandbox Code Playgroud)


Geo*_*ids 7

如果您正在处理 TypeScript 4.1+ 和字符串枚举,并且您想要一个具有编译时和运行时安全性的简单字符串到枚举转换器,那么以下方法很有效:

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
Run Code Online (Sandbox Code Playgroud)


Ham*_*aei 6

对于 Typescript >= 4,此代码有效:

enum Color{
    Red, Green
}

// Conversion :
var green= "Green";
var color : Color = green as unknown as Color; 
Run Code Online (Sandbox Code Playgroud)


Nic*_*ick 5

这个问题有很多混杂的信息,因此让我们在Nick的使用TypeScript的模型中使用枚举指南中介绍 TypeScript 2.x +的整个实现。

本指南适用于:正在创建客户端代码的人员,这些代码正在从服务器中提取一组已知字符串,这些字符串可以方便地在客户端上建模为Enum。

定义枚举

让我们从枚举开始。它看起来应该像这样:

export enum IssueType {
  REPS = 'REPS',
  FETCH = 'FETCH',
  ACTION = 'ACTION',
  UNKNOWN = 'UNKNOWN',
}
Run Code Online (Sandbox Code Playgroud)

这里需要注意的两件事:

  1. 我们明确地将它们声明为字符串支持的枚举类型,这使我们可以使用字符串而不是其他一些无关的数字来实例化它们。

  2. 我们添加了一个服务器模型上可能存在或可能不存在的选项:UNKNOWN。可以按照undefined您的意愿进行处理,但是我希望尽可能避免| undefined使用type来简化处理。

拥有UNKNOWN案例的好处在于,您可以在代码中真正地看到它,并为未知枚举案例创建样式为鲜红色和闪烁的,因此您知道自己未正确处理某些事情。

解析枚举

您可能正在使用嵌入在另一个模型中的枚举,也可能单独使用,但您必须将JSON或XML(ha)中的字符串型枚举解析为强类型的枚举。当嵌入另一个模型中时,此解析器将驻留在类构造函数中。

parseIssueType(typeString: string): IssueType {
  const type = IssueType[typeString];
  if (type === undefined) {
    return IssueType.UNKNOWN;
  }

  return type;
}
Run Code Online (Sandbox Code Playgroud)

如果枚举被正确解析,它将最终成为正确的类型。否则,undefined您可以拦截它并退回您的UNKNOWN案件。如果您希望将其undefined用作未知情况,则可以只返回尝试进行枚举解析的任何结果。

从那里开始,只需使用parse函数和使用新的强类型变量即可。

const strongIssueType: IssueType = parseIssueType('ACTION');
// IssueType.ACTION
const wrongIssueType: IssueType = parseIssueType('UNEXPECTED');
// IssueType.UNKNOWN
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,这似乎是不正确的,或者至少是不能推广的。之所以有效,是因为您的键等于分配给他们的字符串。但是,如果像我的情况那样,它们不同,那么这是行不通的。用[documentation](http://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings)的话来说:*“请记住,字符串枚举成员根本不会生成反向映射。” *您的代码将编译为类似“ IssueType [“ REPS”] =“ REPS”`之类的东西。如果您定义的枚举有所不同,例如,`REPS =“ reps”`,将产生`IssueType [“ REPS”] =“ reps”`,这将... (4认同)

Och*_*aev 5

枚举

enum MyEnum {
    First,
    Second,
    Three
}
Run Code Online (Sandbox Code Playgroud)

使用示例

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

const parsedInvalid= Parser.parseEnum('other', MyEnum);
// parsedInvalid = undefined
Run Code Online (Sandbox Code Playgroud)

忽略区分大小写的解析

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Fun*_*der 5

Typescript 3.9提案

enum Color{ RED, GREEN }

const color = 'RED' as Color;
Run Code Online (Sandbox Code Playgroud)

容易peasy...柠檬挤压!

  • 这是不安全的,`'BANANA' as Color`也会通过 (3认同)