Suggest an editImprove this articleRefine the answer for “What is an enum in TypeScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Enum** in TypeScript is a named set of constants that compiles to a JavaScript object. ```typescript enum Status { Pending, InProgress, Done } // numeric: 0, 1, 2 enum Role { Admin = 'admin', User = 'user' } // string: explicit values const s: Status = Status.Done; // 2 console.log(Status[2]); // 'Done' (reverse mapping, numeric only) ``` **Key:** numeric enums support reverse mapping; string enums do not. Use `const enum` to inline values with no runtime object.Shown above the full answer for quick recall.Answer (EN)Image**Enum** in TypeScript is a set of named constants that compiles to a JavaScript object, giving you type safety instead of raw strings or numbers scattered across your code. ## Theory ### TL;DR - An enum is like a contact list: you call people by name, not by phone number. TypeScript enforces that only valid names are used. - **Numeric enums** auto-increment (0, 1, 2...) and support reverse mapping. **String enums** require explicit values and do not. - `const enum` inlines values at compile time - no runtime object is created. - Use enums for fixed sets like statuses, roles, or directions. For external API data, union types fit better. ### Quick example ```typescript enum Status { Pending = 0, InProgress = 1, Done = 2 } const task: Status = Status.Done; // type-safe console.log(task); // 2 console.log(Status[2]); // 'Done' (reverse mapping) // String enum enum Role { Admin = 'admin', User = 'user' } const userRole: Role = Role.Admin; console.log(userRole); // 'admin' (no reverse mapping) ``` Numeric enums support reverse mapping - `Status[2]` gives `'Done'`. String enums do not. That single difference drives most of the trade-offs below. ### Key difference Numeric enums produce a bidirectional object in JavaScript: name-to-value and value-to-name. So `Status[2]` returns `'Done'`. String enums only map names to values, which makes them predictable with JSON serialization and APIs. The trade-off is giving up the reverse lookup. ### When to use - **Numeric enum:** game states, HTTP status codes, database IDs where you might need reverse lookup - **String enum:** user roles, permission levels, event types that get serialized to JSON or sent over APIs - **const enum:** performance-sensitive paths where values should be inlined and no runtime object is needed - **Union type instead:** when values come from external sources, or you want a compile-time-only solution ### How TypeScript compiles enums TypeScript compiles a numeric enum to a JavaScript object with two sets of entries: `Status['Pending'] = 0` and `Status[0] = 'Pending'`. String enums only get the forward mapping. `const enum` is different - the compiler replaces every reference with the literal value and generates no object at all. So `const myColor = Color.Red` becomes `const myColor = 0` in the output. ### Common mistakes **Mistake 1: Expecting Object.values() on a numeric enum to return just numbers** ```typescript enum Priority { Low, // 0 Medium, // 1 High // 2 } console.log(Object.values(Priority)); // [0, 1, 2, 'Low', 'Medium', 'High'] - both directions are included ``` The numeric enum object stores both `{ 0: 'Low', Low: 0, ... }`, so `Object.values()` returns six items, not three. Filter by type, or switch to a string enum. **Mistake 2: Calling Object.values() on a const enum at runtime** ```typescript const enum Status { Active = 'active', Inactive = 'inactive' } const list = Object.values(Status); // Runtime error: Status is undefined ``` `const enum` has no runtime object. If you need to iterate the values, use a regular enum. **Mistake 3: Mixing numeric and string values in one enum** ```typescript // Avoid: reverse mapping breaks for numeric members enum Mixed { Success = 1, Error = 'error' } ``` Pick one type. Mixed enums break reverse mapping and are hard to read. **Mistake 4: Using enums for external API data** ```typescript enum Role { Admin = 'Admin', // capital A User = 'User' } const fromApi = { role: 'admin' }; // API returns lowercase fromApi.role === Role.Admin; // false - never matches ``` Most "enum not working with API" bugs come down to case mismatch exactly like this. For data from APIs, union types (`type Role = 'admin' | 'user'`) fit better. Or normalize the incoming value before comparing. ### Real-world usage - **React/Redux:** action types (`enum ActionType { FETCH_START = 'FETCH_START' }`) - **Express/Node.js:** HTTP status codes, error types, DB connection states - **NestJS:** role-based access control decorators use enums for permission levels - **GraphQL:** enum types in the schema map directly to TypeScript enums - **Games:** Phaser and Babylon.js use enums for game states, input keys, collision types ### Follow-up questions **Q:** What is the difference between an enum and a union type like `type Status = 'pending' | 'done'`? **A:** Enums create a runtime object and give you a named group you can reference across files. Union types are compile-time only, lighter in the bundle, and better for values that come from external sources. Use enums when you need iteration or reverse mapping. Use union types for simpler cases. **Q:** Why use `const enum` instead of a regular enum? **A:** `const enum` replaces every member reference with its literal value at compile time. No object ends up in the bundle. The downside: you cannot call `Object.values()`, use reverse mapping, or do any runtime reflection on it. **Q:** You have a numeric enum with values 1, 5, and 10. What does `Enum[3]` return? **A:** `undefined`. Reverse mapping only exists for the exact numeric values defined in the enum. Gaps in the sequence have no entries in the JavaScript object. This is a real trap when using numeric enums to convert database IDs back to names - you get `undefined` with no error thrown. **Q:** How do you safely check if a value from an API belongs to a string enum? **A:** `Object.values(MyEnum).includes(apiValue as MyEnum)`. This validates at runtime that the incoming string is one of the allowed values before you treat it as a typed enum member. ## Examples ### Basic: numeric and string enums compared ```typescript enum HttpStatus { OK = 200, BadRequest = 400, NotFound = 404 } // Reverse mapping works for numeric enums const code = 404; console.log(HttpStatus[code]); // 'NotFound' enum OrderStatus { Pending = 'pending', Shipped = 'shipped', Delivered = 'delivered' } // String enum: readable values, clean JSON output const status: OrderStatus = OrderStatus.Shipped; console.log(JSON.stringify({ status })); // {"status":"shipped"} ``` `HttpStatus[404]` returns `'NotFound'` because numeric enums store reverse entries. `OrderStatus` has no reverse mapping but the string values serialize cleanly to JSON. ### Intermediate: type-safe order processing in Express ```typescript enum OrderStatus { Pending = 'pending', Processing = 'processing', Shipped = 'shipped', Delivered = 'delivered' } function handleOrder(status: OrderStatus): string { if (status === OrderStatus.Shipped) { return 'Sending shipping notification'; } // This fails at compile time - TypeScript catches it before runtime: // if (status === OrderStatus.Cancelled) { } // Error: Property 'Cancelled' does not exist return 'No action needed'; } handleOrder(OrderStatus.Shipped); // OK handleOrder('shipped'); // Error: Argument of type 'string' is not assignable to type 'OrderStatus' ``` Passing the raw string `'shipped'` fails even though the value matches, because TypeScript expects `OrderStatus`, not `string`. That is the whole point of using enums.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.