9

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.

4 Answers 4

14

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');
Sign up to request clarification or add additional context in comments.

Comments

4

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

2 Comments

Thank you for your quick response! But can you please explain how { [P in K]: T } equates to an enum type?
@ZachPosten It will equate to a type with keys and values (so basically any object). T will contain the type of values of that type. For an enum object that will be the enum value type. There is no way to make 100% sure the object will be an enum, this just happens to work for enums. (The other answer has the same limitation)
0

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.

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.