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


311

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

enum Color{
    Red, Green
}

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

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

我如何将该值转换为枚举?

Answers:


430

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


111
这不适用于--noImplicitAny(在VS中未选中的“允许隐式'any'类型”)。它error TS7017: Index signature of object type implicitly has an 'any' type.为我产生了这项工作:(var color: Color = (<any>Color)[green];经过1.4版测试)
Vojta 2015年

3
@Vojta说的对。它在VS 2012中不起作用。这一方法可以工作,但可以使用var color:Color =(<any> Color)[green];
Faisal Mq 2015年

3
它不会在这里工作之一,官方文档似乎以确认:typescriptlang.org/docs/handbook/release-notes/...
彼得·德·比耶

26
如果--noImplicitAnyvar color : Color = Color[green as keyof typeof Color];
Jonas,

2
@ Naxos84参见我的answear stackoverflow.com/a/56076148/294242
Jonas,

122

从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


4
所以我们可以使用类型转换:let s = "Green"; let typedColor = <keyof typeof Color> s;
SergeyT

是的,和更换letconst意愿工作,而铸造。更新了示例以澄清这一点。感谢@SergeyT
维克托·

1
typedColorString = Color["Black"];现在返回error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'
多米尼克

2
一条答案:const color: Color = Color[colorString as keyof typeof Color];
cscan

38

如果您确定输入字符串与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团队对较普遍发行的Object string索引的已知限制。


您也可以强制转换为<keyof typeof Color>。另外“0”是输入错误太多,但不会返回undefined,所以检查的typeof mayBeColor ===“号”
昆廷2

@ Quentin2数字字符串呢?即typeof '0'应该是string
帕特里克·迈克尔森

36
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


我不知道为什么,但是此解决方案不适用于const枚举 (使用Typescript 3.8.3)
Robin-Hoodie

30

此注释与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.

我不确定是什么原因引起的,但是如果有人遇到与我同样的问题,我会在这里留下这张纸条。


谢谢!这是一个很愚蠢的问题,很难找出问题所在。也许Typescript应该考虑提出一种更好的处理枚举的方法。
ChickenFeet

24

我使用下面的代码来工作。

var green= "Green";
var color : Color= <Color>Color[green];

23

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

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

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

1
很简单。真好!
Bernoulli IT

1
这可能会产生误导,因为它无法防止无效的颜色。 const colorEnum = "Blue" as Color不会出错,您会以为colorEnum可以。但是,如果console.log要这样做,您会看到“蓝色”。 Artru的回答很好,因为colorEnumundefined-然后您可以专门进行检查。
M Falanga

20

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

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

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

只需使用:

const color = "green" as Color

15

我也遇到了相同的编译器错误。Sly_cardinal的方法稍短一些。

var color: Color = Color[<string>colorId];

作为补充:如果你有一个打字稿枚举通过序列化的枚举作为字符串一个JavaScript层填充(说的通过AngularJS例如ASP网页API),你可以做 myProp.color = Color[<string><any>myProp.color] 干杯
维克多

1
这必须是公认的答案。
米罗斯拉夫·波波夫

9

如果TypeScript编译器知道变量的类型是字符串,则可以这样做:

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

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

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

在运行时,两种解决方案都将起作用。


3
为什么不只使用typecast <string>colorName而不是"" + colorName
SergeyT

7

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

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

定义枚举

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

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

这里有两点注意:

  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;
}

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

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

const strongIssueType: IssueType = parseIssueType('ACTION');
// IssueType.ACTION
const wrongIssueType: IssueType = parseIssueType('UNEXPECTED');
// IssueType.UNKNOWN

6
不幸的是,这似乎是不正确的,或者至少是不能推广的。之所以有效,是因为您的键等于分配给他们的字符串。但是,如果像我的情况那样,它们不同,那么这是行不通的。用文档的话来说:“请记住,字符串枚举成员根本不会生成反向映射。” 您的代码将编译为IssueType["REPS"]="REPS"。如果您对枚举定义了一些不同,例如,REPS="reps"这将产生以下IssueType["REPS"]="reps"结果
altocumulus

...总是返回,IssueType.UNKNOWN因为reps您的枚举中没有键。太糟糕了,我仍然没有找到可行的解决方案,因为我的字符串包含连字符,这使得它们不能用作键。
积云

最后,通过说服编译器这不是字符串枚举,我在此答案中找到了解决方案。可能值得将此信息编辑为您自己的答案。
积云

6

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

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/


这个答案很奇妙!爱它。尤其是从字符串中创建枚举的方式。在测试枚举或其他案例时,这可以节省您太多的键入时间。
Florian Leitgeb

是的,我将其与Jest each一起使用,仅用一种方法测试每个枚举实例
mikeb

6

我一直在寻找一个可以enum从获取的答案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将被退回。
  • 我们强制转换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

注意:而且,正如某人在评论中指出的那样,我也想使用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");

3

枚举

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;
    }
}

像我这样具有枚举的任何人都应该把return enumType[property];您的枚举项目看起来像个案件Skills = "anyvalue"
neustart47 '19

@ neustart47您能问一个问题吗?
ОчирДармаев

这不是问题。我刚刚提到了一些寻找与我相同情况的人的更改。您的回答是正确的。
neustart47

2

以您的方式创建的枚举被编译为一个对象,该对象存储正向(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

1

尝试这个

var color:Color =(任意颜色)[“ Green];

适用于3.5.3版本


0

如果您使用命名空间扩展枚举的功能,则还可以执行以下操作

    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');
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.