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
in stringToEnum<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?
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
in stringToEnum<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?
Share Improve this question asked Jan 25, 2018 at 19:20 sir_thursdaysir_thursday 5,40913 gold badges68 silver badges121 bronze badges 1- Why? Whats your usecase? – Jonas Wilms Commented Jan 25, 2018 at 19:25
3 Answers
Reset to default 11You 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');
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
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;