TypeScript Enums

Enums let you define a set of named constants, giving meaningful names to a fixed collection of related values.

Numeric Enums

By default, TypeScript enums are numeric: the first member is assigned 0, and each subsequent member increments by one unless you specify otherwise.

A Basic Numeric Enum

enum Direction {
  Up,    // 0
  Down,  // 1
  Left,  // 2
  Right, // 3
}

function move(direction: Direction) {
  console.log(`Moving in direction ${direction}`);
}

move(Direction.Up); // "Moving in direction 0"

String Enums

String enums assign a specific string value to each member instead of an auto-incremented number. They are often preferred because their values are readable when logged or serialized, and they don't allow accidental numeric mixing.

A String Enum

enum OrderStatus {
  Pending = "PENDING",
  Shipped = "SHIPPED",
  Delivered = "DELIVERED",
  Cancelled = "CANCELLED",
}

function describeOrder(status: OrderStatus): string {
  switch (status) {
    case OrderStatus.Pending:
      return "Order received, not yet shipped";
    case OrderStatus.Shipped:
      return "On its way";
    case OrderStatus.Delivered:
      return "Delivered successfully";
    case OrderStatus.Cancelled:
      return "Order was cancelled";
  }
}

console.log(describeOrder(OrderStatus.Shipped)); // "On its way"
Note: Prefer string enums over numeric ones for values that might be logged, sent over a network, or stored — the string is self-descriptive, unlike an arbitrary number.

Const Enums

A const enum is fully inlined at compile time and produces no runtime object at all, which can reduce generated JavaScript size. Use it when you don't need to iterate over the enum's values at runtime.

Const Enum Example

const enum LogLevel {
  Info,
  Warning,
  Error,
}

function log(level: LogLevel, message: string) {
  console.log(`[${LogLevel[level]}] ${message}`);
}

log(LogLevel.Warning, "Disk space low");

Enums vs Union Type Literals

AspectEnumUnion of String Literals
Runtime footprintGenerates a JS object (except const enum)No runtime code at all
Reverse mappingAvailable for numeric enumsNot applicable
Syntaxenum Status { Active, Inactive }type Status = "active" | "inactive"
Common recommendationUse for fixed constant sets needing runtime valuesUse for simple type-level constraints
Note: Many teams now prefer union type literals ("active" | "inactive") over enums for simple cases because they add zero runtime overhead — but enums are still valuable when you need actual objects to iterate, log, or reverse-map.

Realistic Use Case: Modeling Permission Levels

Enums are a natural fit for representing a small, fixed set of roles or permission levels used throughout an authorization system.

Permission Levels with an Enum

enum Role {
  Guest = "GUEST",
  Member = "MEMBER",
  Admin = "ADMIN",
}

function canEditContent(role: Role): boolean {
  return role === Role.Admin || role === Role.Member;
}

console.log(canEditContent(Role.Guest)); // false
console.log(canEditContent(Role.Admin)); // true
  • Numeric enums auto-increment starting from 0 unless given explicit values.
  • String enums require every member to have an explicit string value.
  • Const enums are inlined and avoid generating a runtime object.
  • Enum member access is type-checked, preventing typos like Role.Amdin.

Exercise: TypeScript Enums

In a numeric enum with no initializers, what value does the first member get by default?