'Generic function to convert string to typescript enum
I found this great answer about how to convert a string to a typescript enum. Based on that I have written this function
enum Color { Red='red', Green='green' }
function mapColorString(strColor: string): Color {
const colorKey = strColor as keyof typeof Color
return Color[colorKey]
}
But now when I try to make it generic,
function getEnumFromString<T>(str: string): T {
const enumKey = str as keyof T
return T[enumKey]
}
I get the error in the return statement: 'T' only refers to a type, but is being used as a value here.
I want to make this generic because I have a number of enums that I need to generate based on their string values, and I would like to not have a separate method for every one.
Solution 1:[1]
I can get this to work when i pass the enum definition:
enum Color { Red='red', Green='green' }
function getEnumFromString<T>(type: T, str: string): T[keyof T] {
const casted = str as keyof T;
return type[casted];
}
const bar = getEnumFromString(Color, 'Red');
Solution 2:[2]
T
is just going to be the type of the enum. Types are erased and don't exist at runtime. You need to pass in the object representing the enum:
enum Color { Red='red', Green='green' }
function getEnumFromString<T, K extends string>(enumObj: { [P in K]: T },str: string): T {
const enumKey = str as K
return enumObj[enumKey]
}
getEnumFromString(Color, 'Red');
K
will represent the keys of the enum, T
will be the type for the enum value
Solution 3:[3]
This solution seems to work well for me :
/**
* Converts a string value to an enum entry
* @param obj the enum class
* @param str string to convert
* @return enum value or undefined
*/
static stringToEnum<T>(obj: T, str: string) : T[keyof T]
{
return Object.values(obj).includes(str as keyof T) ? str as unknown as T[keyof T] : undefined;
}
Different implementation using native casting, passing through unknown feels jerky though.
Solution 4:[4]
I can create a more generic with ignoring the case.
enum Color { Red='red', Green='green',Test=1,Test2 }
function getEnumFromString<T>(type: T ,str: string): any {
const enumName = (Object.keys(type) as Array<keyof T>).find(k =>(type as any)[k].toLowerCase() === str.toLowerCase()) as keyof T;
var keyValue=isNaN(Number(enumName))? enumName:Number(enumName);
return keyValue;
}
getEnumFromString(Color, 'Test');// output: 1
getEnumFromString(Color, 'Test2');// output: 2
getEnumFromString(Color, 'rEd');//output Red
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Tom Cumming |
Solution 2 | Titian Cernicova-Dragomir |
Solution 3 | Dharman |
Solution 4 | Satish Rabari |