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

时间:2013-06-29 13:45:41

标签: typescript

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

enum Color{
    Red, Green
}

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

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

如何将该值转换为枚举?

23 个答案:

答案 0 :(得分:295)

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

enum Color{
    Red, Green
}

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

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

Try it online

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

答案 1 :(得分:77)

从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

答案 2 :(得分:26)

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

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

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

只需使用:

const color = "green" as Color

答案 3 :(得分:25)

本说明与basarat的answer有关,而非原始问题。

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

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.

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

答案 4 :(得分:18)

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

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
}

Playground

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

  

元素隐含地有任何&#39;类型因为索引表达式的类型不是&#39;数字&#39;。

这意味着默认情况下,TypeScript Enum类型使用数字索引,即 let c = Color[0],但不包含let c = Color["string"]等字符串索引。这是Microsoft团队对更常见问题 Object string indexes 的已知限制。

答案 5 :(得分:18)

我使用以下代码完成了它。

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

答案 6 :(得分:11)

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

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

答案 7 :(得分:8)

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

$(function() {
  $.ajax({
    type: "GET",
    url: "/api/something",
  })
  .done(function(data) {
    $('.targeted').text(data);
  });
});

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

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

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

答案 8 :(得分:7)

最简单的方法

enum Color { Red, Green }

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

这对numericstring枚举均有效。无需使用type assertion

未知的枚举字符串

简单,不安全的变体
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)

转换字符串枚举值

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

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)

Playground sample

答案 9 :(得分:5)

打字稿3.9 提案

enum Color{ RED, GREEN }

const color = 'RED' as Color;

轻松,轻松……柠檬!

答案 10 :(得分:4)

我一直在寻找一个可以从enum获得string的答案,但就我而言,枚举值对应的字符串值不同。 OP对Color有一个简单的枚举,但我有一些不同之处:

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

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

另一个答案

基本上,我想出了另一个受this answer启发的答案:

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

答案 11 :(得分:4)

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

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

定义枚举

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

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

这里需要注意的两件事:

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

  2. 我们添加了一个在服务器模型上可能存在或可能不存在的选项:UNKNOWN。如果愿意,可以将其处理为undefined,但我希望避免在类型上使用| undefined来简化处理。

拥有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

答案 12 :(得分:3)

对于TS 3.9.x

var color : Color = Color[green as unknown as keyof typeof Color];

答案 13 :(得分:2)

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

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

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

答案 14 :(得分:1)

枚举

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

答案 15 :(得分:1)

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

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
}

答案 16 :(得分:1)

尝试

  

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

适用于3.5.3版本

答案 17 :(得分:0)

如果您对类型保护(如果不是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 issue

答案 18 :(得分:0)

如果您正在处理 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

答案 19 :(得分:0)

其他变化可以是

const green= "Green";

const color : Color = Color[green] as Color;

答案 20 :(得分:0)

以您的方式创建的枚举被编译到一个对象中,该对象同时存储前向(name -> value)和反向(value -> name)映射。正如我们从chrome devtools屏幕截图中所观察到的:

enter image description here

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

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

答案 21 :(得分:0)

答案 22 :(得分:-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');