Typescript function to convert string enum member to enum
Solution 1
You can do it all natively without having to write a function:
enum Color {
red,
green,
blue
}
// Enum to string
const redString: string = Color[Color.red];
alert(redString);
// String to enum
const str = 'red';
const redEnum: Color = Color[str];
alert(redEnum);
Or you can have some fun with it...
enum MyEnum {
Foo,
Bar
}
function stringToEnum<ET, T>(enumObj: ET, str: keyof ET): T{
return enumObj[<string>str];
}
const val = stringToEnum<typeof MyEnum, MyEnum>(MyEnum, 'Foo');
// Detects that `foo` is a typo
const val2 = stringToEnum<typeof MyEnum, MyEnum>(MyEnum, 'foo');
Solution 2
Your signature is a bit mixed up. The return type should be T[keyof T]
if you intend for the method to return an enum value. The type of the str
param should also be keyof T
to prevent you from passing invalid strings in, but this will limit you to passing string literals in (or well-typed variables of type keyof T
, but not string
):
function stringToEnum<T>(enumObj: T, str: keyof T): T[keyof T]
Then either don't specify the type param and let the compiler infer the type correctly:
// type: Foo
// value: 0
const result = stringToEnum(MyEnum, 'Foo');
Or you need to provide typeof MyEnum
as the type param:
// type: Foo
// value: 0
const result = stringToEnum<typeof MyEnum>(MyEnum, 'Foo');
If you really want to be able to pass in any arbitrary string enum name, then the return type is a lie: should be T[keyof T] | undefined
. You'll also run into trouble when attempting enumObj[str]
if the type of str
is string
and you have noImplicitAny
compiler option enabled.
There's a bit more to making generic functions that work with enum types properly, especially numeric enums that have reverse lookup entries at run-time. Take a look at the source code for ts-enum-util
(github, npm) for inspiration
Solution 3
stringToEnum(MyEnum, 'Foo');
Just leave away the generic and let typescript do that. Thats because the type stored under MyEnum does not match the Enum itself but is a union type of its values:
enum Test { A, B };
const value: Test /* "A" | "B" */ = Test.A;
sir_thursday
Updated on June 08, 2022Comments
-
sir_thursday almost 2 years
I'd like to write something like this in Typescript:
export function stringToEnum<T>(enumObj: T, str: string): keyof T { return enumObj[str]; }
and use it as follows:
enum MyEnum { Foo } stringToEnum<MyEnum>(MyEnum, 'Foo');
where it would return
MyEnum.Foo
The function above works as expected... but the typings are throwing errors. For the parameter
MyEnum
instringToEnum<MyEnum>(MyEnum, 'Foo');
, Typescript complains tha:Argument of type 'typeof MyEnum' is not assignable to parameter of type 'MyEnum'
which makes sense... unfortunately. Any ideas on how I can get around this?
-
sir_thursday over 6 yearsRight. Is there any way to do it with a method, though?
-
Fenton over 6 yearsI've added an example for fun... the call to the function is significantly trickier than just using
MyEnum['Foo']
. -
JackLeEmmerdeur over 4 yearsHey @Fenton. TS compiler errors out with 7053 in current TS versions, also within your function. This explains it. So the easiest solution would be:
const str: string = 'red'; const redEnum: Color = (<any>Color)[str];
-
JackLeEmmerdeur over 4 yearsIn addition to my last comment: If you got an enum like
enum Color { Red = "red"}
thenconst redEnum: Color = (<any>Color)["red"]
won't match as the indexer matches the enum-member-name. So onlyconst redEnum: Color = (<any>Color)["Red"]
would work.