How to Use Enums in TypeScript
What you’ll build or solve
You’ll create enums using the two common patterns: numeric enums and string enums. By the end, you’ll know which one to pick and how to avoid common enum surprises.
When this approach works best
This method works best when:
Learn TypeScript on Mimo
- You want named constants like
Role.Admininstead of repeating strings. - You share the same set of values across many files and want one definition.
- You need a runtime object, for example to iterate values or reference members.
Avoid enums when:
- You only need a small set of strings for type checking. A union type is often simpler.
Prerequisites
- TypeScript installed
- Basic familiarity with variables and objects
Step-by-step instructions
Step 1: Create a numeric enum
Numeric enums assign numbers automatically, starting at 0.
enumStatus {
Pending,// 0
Approved,// 1
Rejected// 2
}
You can also set a starting value:
enumHttpCode {
Ok=200,
NotFound=404
}
What to look for
- Numeric enums generate a runtime mapping.
- Reverse lookup works for numeric enums, like
Status[0].
Example reverse mapping:
enumDirection {
Up,
Down
}
console.log(Direction[0]);// "Up"
Step 2: Create a string enum
String enums use explicit string values, which makes them easier to read in logs and APIs.
enumRole {
Admin="admin",
Editor="editor",
Viewer="viewer"
}
String enums do not auto-increment. Every member needs a value.
What to look for
- String enums are easier to store and send over an API.
- There is no reverse mapping for string enums.
Examples you can copy
Example 1: Enum for function input
enumTheme {
Light="light",
Dark="dark"
}
functionsetTheme(theme:Theme) {
return`Theme set to${theme}`;
}
setTheme(Theme.Dark);
Example 2: Enum in a switch statement
CSS
enumDirection {
Left="left",
Right="right"
}
functionmove(direction:Direction) {
switch (direction) {
caseDirection.Left:
return"Moving left";
caseDirection.Right:
return"Moving right";
}
}
Example 3: Enum in an object type
enumPriority {
Low="low",
Medium="medium",
High="high"
}
typeTask= {
title:string;
priority:Priority;
};
consttask:Task= {
title:"Pay bills",
priority:Priority.High
};
Common mistakes and how to fix them
Mistake 1: Assigning a raw string instead of an enum member
What someone might do:
enumRole {
Admin="admin",
Editor="editor"
}
letrole:Role="admin";
Why it breaks:
The type is Role, so the value must be a member like Role.Admin.
Correct approach:
letrole:Role=Role.Admin;
Mistake 2: Using numeric enums when you need readable values
What someone might do:
enumStatus {
Pending,
Approved
}
Then save the value to a database expecting strings.
Why it breaks:
You end up storing 0 or 1, which is unclear outside your app.
Correct approach:
enumStatus {
Pending="pending",
Approved="approved"
}
Mistake 3: Using enums when a union type is simpler
What someone might do:
Create an enum for values that never need runtime behavior.
Why it adds friction:
Enums generate runtime code and require extra syntax.
Correct approach:
typeMode="on"|"off";
Use a union when you only need type checking.
Troubleshooting
If TypeScript says a value is not assignable, confirm you used the enum member, like Role.Admin, not a plain string.
If you see unexpected numbers in logs, you are using a numeric enum. Switch to a string enum if you need readable values.
If you rely on reverse mapping like Enum[0], that only works with numeric enums.
If your bundle grows and enums are used heavily, replace small enums with unions when runtime objects are not needed.
Quick recap
- Numeric enums auto-number members and support reverse mapping.
- String enums store readable values and work well for APIs and databases.
- Use enums when you want shared named constants or runtime access.
- Prefer union types when you only need type checking.
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot