我在 TypeScript 中定义了以下枚举:
enum Color{
Red, Green
}
现在在我的函数中,我将颜色作为字符串接收。我尝试了以下代码:
var green= "Green";
var color : Color = <Color>green; // Error: can't convert string to enum
如何将该值转换为枚举?
我在 TypeScript 中定义了以下枚举:
enum Color{
Red, Green
}
现在在我的函数中,我将颜色作为字符串接收。我尝试了以下代码:
var green= "Green";
var color : Color = <Color>green; // Error: can't convert string to enum
如何将该值转换为枚举?
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
从 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
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
如果您为枚举提供字符串值,则直接转换就可以了。
enum Color {
Green = "Green",
Red = "Red"
}
const color = "Green";
const colorEnum = color as Color;
假设您使用打字稿:上面的许多解决方案可能不起作用或过于复杂。
情况:字符串与枚举值不同(大小写不同)
enum Color {
Green = "green",
Red = "red"
}
只需使用:
const color = "green" as Color
请注意,这并不能保证有效的枚举。
如果您确定输入字符串与 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 团队对更普遍的问题对象字符串索引的已知限制。
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
我使用以下代码使其工作。
var green= "Green";
var color : Color= <Color>Color[green];
本说明与 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.
我不确定是什么导致了这个问题,但我会在此处留下此说明,以防有人遇到与我相同的问题。
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)
我也遇到了同样的编译器错误。只是 Sly_cardinal 方法的稍微短一些的变化。
var color: Color = Color[<string>colorId];
如果 TypeScript 编译器知道变量的类型是字符串,那么这可以工作:
let colorName : string = "Green";
let color : Color = Color[colorName];
否则,您应该将其显式转换为字符串(以避免编译器警告):
let colorName : any = "Green";
let color : Color = Color["" + colorName];
在运行时,两种解决方案都可以工作。
我正在寻找一个可以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");
我需要知道如何遍历枚举值(正在测试多个枚举的大量排列),我发现这很好用:
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/
这个问题有很多混合信息,所以让我们在Nick's Guide to Using Enums in Models with TypeScript 中介绍 TypeScript 2.x+ 的整个实现。
本指南适用于:创建客户端代码的人,这些代码从服务器获取一组已知字符串,这些字符串可以方便地建模为客户端的枚举。
让我们从枚举开始。它应该看起来像这样:
export enum IssueType {
REPS = 'REPS',
FETCH = 'FETCH',
ACTION = 'ACTION',
UNKNOWN = 'UNKNOWN',
}
这里需要注意两点:
我们明确地将这些声明为字符串支持的枚举案例,这允许我们用字符串而不是其他一些不相关的数字来实例化它们。
我们添加了一个选项,该选项可能存在也可能不存在于我们的服务器模型中: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
对于 TS 3.9.x
var color : Color = Color[green as unknown as keyof typeof Color];
如果您正在处理 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
以您的方式创建的枚举被编译成一个存储正向(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
枚举
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;
}
}
大多数这些答案对我来说似乎过于复杂......
您可以简单地在枚举上创建一个解析函数,该函数期望其中一个键作为参数。添加新颜色后,无需进行其他更改
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');
尝试这个
var color : Color = (Color as any)["Green];
这适用于 3.5.3 版本
Typescript 3.9提案
enum Color{ RED, GREEN }
const color = 'RED' as Color;
简单的...柠檬汁!
如果您对类型保护感兴趣,否则将是 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 问题
其他变化可以是
const green= "Green";
const color : Color = Color[green] as Color;
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"
对于 Typescript >= 4,此代码有效:
enum Color{
Red, Green
}
// Conversion :
var green= "Green";
var color : Color = green as unknown as Color;
如果您使用命名空间来扩展枚举的功能,那么您还可以执行类似的操作
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');