Question
I have defined the following enum in TypeScript:
enum Color {
Red,
Green
}
In a function, I receive a color value as a string. For example:
const green = "Green";
const color: Color = <Color>green; // Error: cannot convert string to enum
How can I safely convert a string value like "Green" into the corresponding Color enum value in TypeScript?
Short Answer
By the end of this page, you will understand why a plain string cannot be directly cast to a TypeScript enum, how enum lookup works, and how to safely convert strings into enum values using validation. You will also learn common patterns used in real TypeScript codebases to avoid runtime bugs.
Concept
TypeScript enums are named sets of constant values. In your example:
enum Color {
Red,
Green
}
Color.Red is actually 0, and Color.Green is 1 because numeric enums start at 0 by default.
That means this enum is not storing the strings "Red" and "Green". It is storing numeric values with named members.
So when you write:
const green = "Green";
const color: Color = green as Color;
TypeScript may allow a type assertion in some cases, but that does not actually convert the string at runtime. A type assertion only tells the compiler, "trust me." It does not change the value.
This matters because:
"Green"is a stringColor.Greenis the number1- assigning one to the other without conversion is unsafe
To convert a string to an enum, you usually need to look up the enum member by its name:
const color = Color[green as keyof typeof Color];
For numeric enums, this returns the numeric enum value.
However, because user input can be invalid, real code should also validate the string before using it.
Mental Model
Think of an enum like a labeled storage rack:
- The label
Redpoints to value0 - The label
Greenpoints to value1
If someone gives you the text "Green", you do not automatically have the value 1. You first need to go to the rack and ask:
"Do you have a label named
Green? If yes, give me the value behind it."
That is what enum lookup does.
A type assertion like green as Color is like writing 1 on a sticky note and placing it on top of the string. The original value is still just the string "Green". Nothing has been converted.
Syntax and Examples
Basic enum lookup
enum Color {
Red,
Green
}
const input = "Green";
const color = Color[input as keyof typeof Color];
console.log(color); // 1
console.log(color === Color.Green); // true
How it works
typeof Colorgets the type of the enum objectkeyof typeof Colormeans the valid enum keys:"Red" | "Green"Color[input as keyof typeof Color]looks up the member by name
Safer version with validation
enum Color {
Red,
Green
}
function parseColor(value: string): Color | undefined {
if (value in Color && isNaN(Number(value))) {
return Color[value as keyof typeof Color] as Color;
}
return undefined;
}
console.log(parseColor("Green")); // 1
console.log(parseColor("Blue")); // undefined
This is safer because it does not assume every string is valid.
String enum example
Sometimes you want the enum values themselves to be strings:
enum Color {
Red = "Red",
Green = "Green"
}
function parseColor(value: string): Color | undefined {
if (Object.values(Color).includes(value as Color)) {
return value as Color;
}
return undefined;
}
console.log(parseColor("Green")); // "Green"
With a string enum, the value is already a string, so conversion is often simpler.
Step by Step Execution
Consider this example:
enum Color {
Red,
Green
}
const input = "Green";
const result = Color[input as keyof typeof Color];
Here is what happens step by step:
- TypeScript compiles the numeric enum into an object similar to this:
{
0: "Red",
1: "Green",
Red: 0,
Green: 1
}
-
inputcontains the string"Green". -
input as keyof typeof Colortells TypeScript to treatinputas a valid enum key. -
Color["Green"]is evaluated. -
The enum object returns
1. -
resultnow contains1, which is the value ofColor.Green.
So:
console.log(result); // 1
console.log(result === Color.Green); // true
If the input were "Blue", then:
Color["Blue" as keyof typeof Color]
would return undefined at runtime, which is why validation is important.
Real World Use Cases
String-to-enum conversion is common whenever your program receives text from outside your code.
Common examples
- API request parameters: a query string might contain
"Green" - Form input: a dropdown or text field may send enum names as strings
- Configuration files: JSON often stores values as strings
- URL parameters:
/products?color=Green - Environment variables: values always arrive as strings
- CLI tools: command-line options are text input
Example: parsing an API filter
enum Status {
Pending,
Approved,
Rejected
}
function parseStatus(value: string): Status | undefined {
if (value in Status && isNaN(Number(value))) {
return Status[value as keyof typeof Status] as Status;
}
return undefined;
}
This helps convert external text into a controlled internal value your app can trust.
Real Codebase Usage
In real projects, developers rarely cast raw input directly. They usually wrap conversion in a helper function and validate the input first.
Common patterns
Guard clause
function parseColor(value: string): Color | undefined {
if (!(value in Color) || !isNaN(Number(value))) {
return undefined;
}
return Color[value as keyof typeof Color] as Color;
}
This rejects invalid input early.
Validation before business logic
const parsedColor = parseColor(userInput);
if (parsedColor === undefined) {
throw new Error("Invalid color value");
}
saveColor(parsedColor);
Mapping external values to internal enums
Sometimes incoming values do not match enum member names exactly.
enum Color {
Red,
Green
}
const colorMap: Record<string, Color> = {
red: Color.Red,
green: Color.Green
};
function parseColor(value: string): Color | undefined {
return colorMap[value.toLowerCase()];
}
This is very common when handling user input that may use lowercase or different formatting.
Prefer string enums for external data
If your app exchanges values with APIs or JSON, string enums are often easier to work with:
enum Color {
Red = "Red",
Green = "Green"
}
They are more readable and avoid confusion caused by numeric values like 0 and 1.
Common Mistakes
1. Thinking as converts the value
Broken example:
enum Color {
Red,
Green
}
const input = "Green";
const color = input as Color;
Problem:
- This does not convert
"Green"into1 - It only changes what TypeScript believes about the type
2. Skipping validation
Broken example:
const input = "Blue";
const color = Color[input as keyof typeof Color];
console.log(color); // undefined
Problem:
- invalid input leads to
undefined - later code may fail unexpectedly
Fix it by checking first.
function parseColor(value: string): Color | undefined {
if (value in Color && isNaN(Number(value))) {
return Color[value as keyof typeof Color] as Color;
}
return undefined;
}
3. Forgetting that numeric enums have reverse mappings
Numeric enums create both key-to-value and value-to-key mappings. That can make checks like value in Color slightly confusing, because numbers also appear as keys on the enum object.
4. Using enum names when values are actually strings
If you define:
enum Color {
Red = "RED",
Green = "GREEN"
}
Then "Green" is not a valid enum value. The valid values are "RED" and "GREEN".
5. Ignoring case differences
Broken example:
parseColor("green");
If your enum key is Green, lowercase green will not match unless you normalize the input.
function parseColor(value: string): Color | undefined {
const normalized = value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();
if (normalized in Color) {
return Color[normalized as keyof typeof Color] as Color;
}
return undefined;
}
Comparisons
Enum conversion approaches
| Approach | Works for numeric enum | Works for string enum | Safe by default | Notes |
|---|---|---|---|---|
value as Color | No real conversion | No real conversion | No | Type assertion only |
Color[value as keyof typeof Color] | Yes | Looks up by key, not value | No | Add validation |
Object.values(Color).includes(value as Color) | Limited | Yes | Better | Useful for string enums |
| Manual map object | Yes | Yes | Yes | Great for normalization and custom input |
Numeric enum vs string enum
| Enum type | Example value | Good for | Drawback |
|---|---|---|---|
| Numeric enum | Color.Green === 1 | internal flags or compact values | less readable when serialized |
| String enum | Color.Green === "Green" | APIs, JSON, config, logs | slightly more verbose |
Enum vs union of string literals
| Option | Example | Benefit | Limitation |
|---|---|---|---|
| Enum | enum Color { Red = "Red" } | named constants and grouping | extra runtime object |
| String union | `type Color = "Red" | "Green"` | simple and lightweight |
In many modern TypeScript codebases, string unions are often preferred when you only need type safety and not enum behavior.
Cheat Sheet
Numeric enum lookup
enum Color {
Red,
Green
}
const input = "Green";
const color = Color[input as keyof typeof Color]; // 1
Safe parser for numeric enum
function parseColor(value: string): Color | undefined {
if (value in Color && isNaN(Number(value))) {
return Color[value as keyof typeof Color] as Color;
}
return undefined;
}
String enum parser
enum Color {
Red = "Red",
Green = "Green"
}
function parseColor(value: string): Color | undefined {
return Object.values(Color).includes(value as Color)
? (value as Color)
: undefined;
}
Key rules
asdoes not convert values at runtime- numeric enums store numbers by default
Color["Green"]works because enum keys are object properties- validate external input before using it
- prefer string enums for API and JSON data
- use a manual mapping object when you need case-insensitive or custom parsing
Common edge cases
"green"does not match"Green"- invalid keys return
undefined - numeric enums have reverse mappings
- string enums do not have reverse mappings like numeric enums do
FAQ
How do I convert a string to an enum in TypeScript?
Use enum lookup or a parser function. For a numeric enum, Color[input as keyof typeof Color] looks up the enum member by name.
Why does as Color not work?
Because type assertions only affect TypeScript's type checking. They do not transform the runtime value.
What happens if the string does not match an enum member?
The lookup usually returns undefined, so you should validate the input first.
Is a string enum easier to use than a numeric enum?
Usually yes, especially for API data, JSON, and form values, because the runtime values are readable strings.
Can I do case-insensitive enum parsing?
Yes. Normalize the input first, or use a mapping object like { green: Color.Green }.
Should I use enums or string literal unions?
If you only need type safety, string literal unions are often simpler. If you want a grouped runtime object, enums can be useful.
Do numeric enums and string enums behave the same way?
No. Numeric enums support reverse mapping. String enums do not behave the same way at runtime.
Mini Project
Description
Build a small TypeScript utility that parses user-provided color strings into enum values. This demonstrates safe conversion, input normalization, and validation, which are all common when handling form input, query parameters, or API values.
Goal
Create a reusable parseColor function that converts a string into a valid Color enum value or returns undefined when the input is invalid.
Requirements
- Define a
Colorenum with at leastRed,Green, andBlue. - Accept user input as a string.
- Support case-insensitive input such as
"green"or"GREEN". - Return
undefinedfor invalid values. - Print a message showing whether parsing succeeded.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.