TypeScript: TypeScript enum (enum)
Last updated: 2026-08-26
Enums are one of the few TypeScript type features that have runtime behavior—they are both a type and generate actual JavaScript objects.
1. Numeric Enumeration
(1) Basic Syntax
enum Direction {
Up, // 0(Auto-increment from 0)
Down, // 1
Left, // 2
Right // 3
}
let dir: Direction = Direction.Up;
console.log(dir); // 0
console.log(Direction[0]); // "Up"(Inverse Mapping)
(2) Custom Initial Values
enum Status {
Active = 1, // 1
Inactive, // 2(Auto-increment)
Pending // 3
}
enum HttpStatus {
OK = 200,
Moved = 301,
BadRequest = 400,
NotFound = 404,
ServerError = 500
}
let code: HttpStatus = HttpStatus.OK;
console.log(code); // 200
(3) Reverse Mapping of Numeric Enumerations
After compilation, numeric enumerations generate bidirectional mapping objects—you can retrieve a value by its name, or a name by its value:
enum Role {
Admin = 0,
Editor = 1,
Viewer = 2
}
// Forward Mapping: name → value
console.log(Role.Admin); // 0
// Inverse Mapping: value → name
console.log(Role[0]); // "Admin"
console.log(Role[1]); // "Editor"
JavaScript generated after compilation:
var Role;
(function (Role) {
Role[Role["Admin"] = 0] = "Admin";
Role[Role["Editor"] = 1] = "Editor";
Role[Role["Viewer"] = 2] = "Viewer";
})(Role || (Role = {}));
2. String Enumeration
(1) Basic Syntax
Each member of a string enumeration must be explicitly assigned—there is no automatic increment:
enum EventType {
Click = "click",
Change = "change",
Submit = "submit",
Focus = "focus"
}
let event: EventType = EventType.Click;
console.log(event); // "click"
(2) String enumeration has no inverse mapping
enum Color {
Red = "RED",
Green = "GREEN",
Blue = "BLUE"
}
console.log(Color.Red); // "RED" ✅ Forward Mapping
// console.log(Color["RED"]); // undefined ❌ String enumeration has no reverse mapping
▶ Example: Defining Order Statuses Using an Enumeration
enum OrderStatus {
Pending = "PENDING",
Processing = "PROCESSING",
Shipped = "SHIPPED",
Delivered = "DELIVERED",
Cancelled = "CANCELLED"
}
function getStatusLabel(status: OrderStatus): string {
switch (status) {
case OrderStatus.Pending: return "Pending";
case OrderStatus.Processing: return "Processing...";
case OrderStatus.Shipped: return "Shipped";
case OrderStatus.Delivered: return "Delivered";
case OrderStatus.Cancelled: return "Canceled";
}
}
let currentStatus: OrderStatus = OrderStatus.Processing;
console.log(`Current Status:${getStatusLabel(currentStatus)}`);
console.log(`Status Code:${currentStatus}`);
Output:
Current Status:Processing...
Status Code:PROCESSING
3. Heterogeneous Enumerations
Enumerations can contain a mix of numeric and string values—but this is not recommended:
enum Mixed {
No = 0,
Yes = "YES"
}
4. const Enumerations
const enum Replaced by an inline expression during compilation—does not generate a JavaScript object, offering better performance but with limited functionality:
(1) Basic Syntax
const enum Color {
Red = "RED",
Green = "GREEN",
Blue = "BLUE"
}
let c = Color.Red;
// After compilation:let c = "RED"(Direct Inline Replacement,No enumeration objects)
(2) Limitations of const Enumerations
const enum Direction {
Up = "UP",
Down = "DOWN"
}
// ❌ const Enumerations cannot use reverse mapping.
// console.log(Direction[0]);
// ❌ const Enumerations cannot be iterated over at runtime
// for (let d in Direction) { }
// ✅ Only simple value references are allowed.
let dir = Direction.Up; // Compile to let dir = "UP"
(3) The preserveConstEnums option
If you want const enumerations to not be inlined but to retain the enumeration objects, enable preserveConstEnums: true:
// tsconfig.json
// "preserveConstEnums": true
const enum Status {
Active = 1
}
let s = Status.Active;
// After compilation:Enumeration objects are still generated(But quotes are also inlined.)
5. Runtime and Type Safety of Enumerations
(1) Enumerations as Types
enum Role {
Admin,
Editor,
Viewer
}
function checkAccess(role: Role): boolean {
return role === Role.Admin || role === Role.Editor;
}
checkAccess(Role.Admin); // ✅
checkAccess(0); // ✅ Numeric enumerations accept numeric values(but ⚠️ not recommended)
// checkAccess(99); // ✅ Compilation successful!Any number can be converted to——This is a numeric enumeration vulnerability.
let r: Role = 99 is a valid value. This is because numeric enumerations are designed with bit flags in mind. If you need strict value constraints, use string enumerations or literal union types.
(2) String enumeration is safer
enum Role {
Admin = "ADMIN",
Editor = "EDITOR",
Viewer = "VIEWER"
}
let r: Role = Role.Admin; // ✅
// r = "ADMIN"; // ❌ String enumeration does not accept regular strings.
// r = "SUPERADMIN"; // ❌ Only enumeration members are accepted
6. Enumerations vs. Literal Union Types
| Property | Enumeration | Literal Union Type |
|---|---|---|
| Runtime code | Yes (objects are created) | No (pure types) |
| Reverse Mapping | Digital Enumeration: Yes | No |
| Iterate through all values | Yes | No |
| Value Constraints | Numeric Enumeration (Looser) | Strict |
| Code Hints | Enum Member Autocomplete | Union Value Autocomplete |
| Bundle size | Increases code size | Zero size |
| Interoperability with JS | Enumeration values are custom objects | Native strings/numbers |
(1) Scenarios for Using Enumerations
- A reverse mapping (value → name) is required
- All values must be iterated over at runtime
- Enumerations are required for use as runtime objects (such as API constant mappings)
(2) Scenarios Using Literal Union Types (Recommended as the First Choice)
- Only type constraints are required
- Requires interoperability with native JavaScript strings and numbers
- Aim for the smallest bundle size
- No runtime behavior required
▶ Example: Comparison of the Two Methods
// Method 1:Enumeration
enum Direction1 {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
// Method 2:Literal Union Types(Recommendations)
type Direction2 = "UP" | "DOWN" | "LEFT" | "RIGHT";
// The two are equivalent in terms of type constraints.
function move1(dir: Direction1): void { console.log(dir); }
function move2(dir: Direction2): void { console.log(dir); }
move1(Direction1.Up); // ✅ "UP"
move2("UP"); // ✅ Use the string directly,Even simpler
// But enumerations can be iterated over
console.log(Object.values(Direction1));
// ["UP", "DOWN", "LEFT", "RIGHT"]
// Literal union types cannot be iterated over(Pure compile-time types)
Output:
UP
UP
["UP", "DOWN", "LEFT", "RIGHT"]
▶ Example: Const Enums for Zero-Cost Type Safety
const enum LogLevel {
Debug = 0,
Info = 1,
Warn = 2,
Error = 3
}
function log(level: LogLevel, message: string): void {
const prefix = ["DEBUG", "INFO", "WARN", "ERROR"][level];
console.log(`[${prefix}] ${message}`);
}
log(LogLevel.Info, "Server started"); // Compiles to: log(1, "Server started")
log(LogLevel.Error, "Connection lost"); // Compiles to: log(3, "Connection lost")
Output:
[INFO] Server started
[ERROR] Connection lost
const enum members are inlined at compile time—no enum object is emitted in the JS output, resulting in smaller bundle size.
❓ FAQ
enum Perm { Read = 1, Write = 2, Execute = 4 }), and bit combinations Read | Write = 3 are valid but not included in the enumeration definition. Therefore, the numeric enumeration type has relaxed its constraints. If you do not want this behavior, use string enumerations or literal union types.const enum and a regular enum?const enum is inlined at compile time—Color.Red is directly replaced with "RED", and no enum object is generated. The advantage is a smaller bundle size and faster runtime performance; the disadvantage is that it cannot be reverse-mapped, cannot be iterated over, and cannot be used in dynamic contexts. Prioritize using const enumerations (unless you need runtime features).interface Config { role: Role }. Enumeration members can also be used as members of union types—type Mixed = Role.Admin | "superadmin". Enumerations are a unified concept of type and value, offering flexible usage.📖 Summary
- Numeric enumerations automatically increment from 0 and support reverse mapping; string enumerations must be explicitly assigned and do not support reverse mapping.
- Heterogeneous enumerations (mixing numbers and strings) are not recommended
- Const enumerations are inlined at compile time, resulting in zero runtime overhead, but with limited functionality
- Numeric enumeration types can accept any number (a design flaw), while string enumerations are more restrictive
- In most cases, it is recommended to use literal union types instead of enumerations—they are lighter, safer, and take up zero space.
- Use enumeration only when you need to map values in reverse or iterate through all values.
📝 Exercises
- Basic Problem (Difficulty ⭐): Given a string enum
Season(Spring/Summer/Autumn/Winter), write a function that returns a description of the corresponding month range based on the season. - Advanced Exercise (Difficulty ⭐⭐): Use
const enumto define HTTP methods (GET/POST/PUT/DELETE), then define anRequestinterface that includesmethodandurlproperties. Create several request objects to verify the type constraints. - Challenge (Difficulty: ⭐⭐⭐): Use literal union types instead of enumerations to implement a "permissions system": Define
Permission = "read" | "write" | "execute" | "admin", then implement thehasPermission(userPerms: Permission[], required: Permission): booleanfunction to check whether a user has a specific permission (admin has all permissions).