531

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

enum Color{
    Red, Green
}

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

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

如何将该值转换为枚举?

4

26 回答 26

613

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

enum Color{
    Red, Green
}

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

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

在线尝试

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

于 2013-06-29T14:04:00.847 回答
204

从 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];

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

于 2017-03-06T11:02:11.060 回答
114
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

此示例适用--noImplicitAny于 TypeScript

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

于 2019-05-10T10:51:33.303 回答
102

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

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

const color = "Green";
const colorEnum = color as Color;
于 2019-11-30T13:07:49.100 回答
68

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

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

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

只需使用:

const color = "green" as Color

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

于 2020-01-10T16:20:52.800 回答
58

打字稿 1.x

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

const color: Color = (<any>Color)["Red"];

如果输入字符串可能与 Enum 不匹配,请使用:

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

操场


如果我们不enum强制<any>类型转换,那么 TypeScript 将显示错误:

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

这意味着默认情况下,TypeScript Enum 类型适用于数字索引,即 let c = Color[0],但不适用于字符串索引,如let c = Color["string"]. 这是 Microsoft 团队对更普遍的问题对象字符串索引的已知限制。

打字稿 2.x-4x

TypeScript 转向了这个keyof typeof概念。

如果有些使用字符串值枚举:

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

然后是通过访问枚举成员将键映射到值(Color.Green ->“GRN”)的语言解决方案,但是没有简单的方法来执行相反的操作(“GRN”-> Color.Green)。从反向映射

请记住,字符串枚举成员根本不会生成反向映射。

一种可能的解决方案是手动检查值并将值转换为枚举。请注意,它仅适用于字符串枚举。

function enumFromStringValue<T> (enm: { [s: string]: T}, value: string): T | undefined {
  return (Object.values(enm) as unknown as string[]).includes(value)
    ? value as unknown as T
    : undefined;
}

enumFromStringValue(Color, "RD"); // Color.Red
enumFromStringValue(Color, "UNKNOWN"); // undefined
enumFromStringValue(Color, "Red"); // undefined
于 2017-01-09T12:47:53.760 回答
31

我使用以下代码使其工作。

var green= "Green";
var color : Color= <Color>Color[green];
于 2013-06-29T13:50:01.560 回答
31

本说明与 basarat 的回答有关,而不是原始问题。

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

var colorId = myOtherObject.colorId; // value "Green";
var color: Color = <Color>Color[colorId]; // TSC error here: Cannot convert string to Color.

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

var colorId = <string>myOtherObject.colorId; // Force string value here
var color: Color = Color[colorId]; // Fixes lookup here.

我不确定是什么导致了这个问题,但我会在此处留下此说明,以防有人遇到与我相同的问题。

于 2013-12-17T12:54:31.763 回答
23

最简单的方法

enum Color { Red, Green }

const c1 = Color["Red"]
const redStr = "Red" // important: use `const`, not mutable `let`
const c2 = Color[redStr]

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

未知的枚举字符串

简单、不安全的变体
const redStrWide: string = "Red" // wide, unspecific typed string
const c3 = Color[redStrWide as keyof typeof Color]
带检查的安全变体
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)

转换字符串枚举值

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

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)

游乐场样本

于 2020-07-09T10:34:57.803 回答
18

我也遇到了同样的编译器错误。只是 Sly_cardinal 方法的稍微短一些的变化。

var color: Color = Color[<string>colorId];
于 2015-08-20T12:20:18.720 回答
17

如果 TypeScript 编译器知道变量的类型是字符串,那么这可以工作:

let colorName : string = "Green";
let color : Color = Color[colorName];

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

let colorName : any = "Green";
let color : Color = Color["" + colorName];

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

于 2016-08-17T06:37:15.550 回答
14

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

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

当您尝试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]];

笔记

  • 我们采用 的第一个结果filter假设客户端从枚举中传递了一个有效字符串。如果不是这样,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.

更新后的版本

没有强制转换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];

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

stringToEnumValue(Gender, "Can't tell");
于 2019-09-03T18:31:05.237 回答
10

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

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/

于 2019-07-02T14:39:13.000 回答
8

这个问题有很多混合信息,所以让我们在Nick's Guide to Using Enums in Models with TypeScript 中介绍 TypeScript 2.x+ 的整个实现。

本指南适用于:创建客户端代码的人,这些代码从服务器获取一组已知字符串,这些字符串可以方便地建模为客户端的枚举。

定义枚举

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

export enum IssueType {
  REPS = 'REPS',
  FETCH = 'FETCH',
  ACTION = 'ACTION',
  UNKNOWN = 'UNKNOWN',
}

这里需要注意两点:

  1. 我们明确地将这些声明为字符串支持的枚举案例,这允许我们用字符串而不是其他一些不相关的数字来实例化它们。

  2. 我们添加了一个选项,该选项可能存在也可能不存在于我们的服务器模型中:UNKNOWN. 这可以按照undefined您的喜好进行处理,但我希望尽可能避免| undefined使用类型以简化处理。

拥有一个UNKNOWN案例的好处在于,您可以在代码中非常明显地看到它,并为未知的枚举案例制作亮红色和闪烁的样式,这样您就知道自己没有正确处理某些事情。

解析枚举

您可能正在使用嵌入在另一个模型中的这个枚举,或者单独使用这个枚举,但是您将不得不将来自 JSON 或 XML (ha) 的 string-y 类型枚举解析为您的强类型对应项。当嵌入到另一个模型中时,这个解析器存在于类构造函数中。

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

  return type;
}

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

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

const strongIssueType: IssueType = parseIssueType('ACTION');
// IssueType.ACTION
const wrongIssueType: IssueType = parseIssueType('UNEXPECTED');
// IssueType.UNKNOWN
于 2018-10-22T15:40:59.330 回答
7

对于 TS 3.9.x

var color : Color = Color[green as unknown as keyof typeof Color];
于 2020-08-14T17:48:14.743 回答
5

如果您正在处理 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
于 2021-07-01T17:02:37.730 回答
5

以您的方式创建的枚举被编译成一个存储正向(name -> value)和反向(value -> name)映射的对象。我们可以从这个 chrome devtools 截图中观察到:

在此处输入图像描述

这是双重映射如何工作以及如何从一个映射到另一个映射的示例:

enum Color{
    Red, Green
}
// To Number
var greenNr: number = Color['Green'];
console.log(greenNr); // logs 1

// To String
var greenString: string = Color[Color['Green']];  // or Color[Color[1]
console.log(greenString); // logs Green

// In your example

// recieve as Color.green instead of the string green
var green: string = Color[Color.Green];  

// obtain the enum number value which corresponds to the Color.green property
var color: Color = (<any>Color)[green];  

console.log(color); // logs 1
于 2019-07-05T12:41:12.877 回答
5

枚举

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;
    }
}
于 2019-06-21T15:35:21.757 回答
4

大多数这些答案对我来说似乎过于复杂......

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

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');
于 2021-09-10T10:21:26.273 回答
4

尝试这个

var color : Color = (Color as any)["Green];

这适用于 3.5.3 版本

于 2019-08-15T09:06:03.650 回答
3

Typescript 3.9提案

enum Color{ RED, GREEN }

const color = 'RED' as Color;

简单的...柠檬汁!

于 2020-07-22T15:34:37.580 回答
3

如果您对类型保护感兴趣,否则将是 a string(这就是我遇到这个问题的方式),这可能对您有用:

enum CurrencyCode {
  cad = "cad",
  eur = "eur",
  gbp = "gbp",
  jpy = "jpy",
  usd = "usd",
}

const createEnumChecker = <T extends string, TEnumValue extends string>(
  enumVariable: { [key in T]: TEnumValue }
) => {
  const enumValues = Object.values(enumVariable);
  return (value: string | number | boolean): value is TEnumValue =>
    enumValues.includes(value);
};

const isCurrencyCode = createEnumChecker(CurrencyCode);

const input: string = 'gbp';

let verifiedCurrencyCode: CurrencyCode | null = null;
// verifiedCurrencyCode = input;
// ^ TypeError: Type 'string' is not assignable to type 'CurrencyCode | null'.

if (isCurrencyCode(input)) {
  verifiedCurrencyCode = input; // No Type Error 
}

解决方案取自讨论通用枚举的这个github 问题

于 2020-11-18T20:25:20.890 回答
2

其他变化可以是

const green= "Green";

const color : Color = Color[green] as Color;
于 2020-06-18T21:13:58.687 回答
2

It works for me in TypeScript 4.4.3 TS Playground link.

  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"

于 2021-10-05T19:17:28.623 回答
0

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

enum Color{
    Red, Green
}

// Conversion :
var green= "Green";
var color : Color = green as unknown as Color; 
于 2021-12-11T17:28:05.230 回答
-1

如果您使用命名空间来扩展枚举的功能,那么您还可以执行类似的操作

    enum Color {
        Red, Green
    }

    export namespace Color {
      export function getInstance(color: string) : Color {
        if(color == 'Red') {
          return Color.Red;
        } else if (color == 'Green') {
          return Color.Green;
        }
      }
    }

并像这样使用它

  Color.getInstance('Red');
于 2020-05-03T10:10:43.183 回答