TypeScript Enums
Naming a fixed set of related values with enum, and how numeric and string enums differ.
2 min read
An enum (short for enumeration) names a fixed set of related constant values as a single type — a dedicated language construct for something you could also model with a string-literal union, as covered in a previous lesson.
Numeric enums
enum Direction {
Up,
Down,
Left,
Right,
}
let move: Direction = Direction.Up;
console.log(move); // 0By default, members are assigned increasing numbers starting at 0 — Up is 0, Down is 1, and so on. You can set a starting value, and the rest continue from there:
enum Direction {
Up = 1,
Down, // 2
Left, // 3
Right, // 4
}String enums
enum Status {
Pending = "PENDING",
Active = "ACTIVE",
Closed = "CLOSED",
}
let status: Status = Status.Active;
console.log(status); // "ACTIVE"String enums don't auto-increment — every member needs its own explicit value — but they're generally preferred over numeric enums for real code: the value logged, sent over the network, or shown in a debugger is a readable string ("ACTIVE") instead of an opaque number (1), which makes bugs and logs much easier to read.
What an enum compiles to
Unlike most TypeScript type-level constructs, an enum isn't erased at compile time — it generates real JavaScript objects and code that exist at runtime:
// Roughly what the Direction numeric enum compiles to
var Direction;
(function (Direction) {
Direction[(Direction["Up"] = 0)] = "Up";
Direction[(Direction["Down"] = 1)] = "Down";
})(Direction || (Direction = {}));That reverse mapping (numeric enums let you go from the number back to the name: Direction[0] === "Up") is a real, if rarely used, runtime feature — string enums don't get this reverse mapping.
enum vs a union of string literals
// enum
enum Status { Pending = "PENDING", Active = "ACTIVE" }
// union of string literals
type Status = "PENDING" | "ACTIVE";The union version has no runtime footprint at all — it's purely a compile-time construct, erased like every other type — and it works directly with plain string values without needing Status.Active everywhere. Modern TypeScript style guides increasingly favor string-literal unions over enums for exactly that reason: no generated code, no import needed just to reference a value, and it composes more naturally with the rest of the type system (narrowing, discriminated unions) covered elsewhere in this course. enum still shows up often in existing codebases and in some APIs (including parts of TypeScript's own ecosystem), so recognizing it matters even if you default to unions in new code.
The next lesson covers generics — writing a type or function that works across many types instead of one fixed type.