Back to roadmaps typescript Course

Enums and Literal Types

When you need to define a variable that can only hold a specific, limited set of values, TypeScript offers two main solutions: Enums and Literal Types.


1. What are Enums?

Enums (Enumerations) allow you to define a set of named constants. This makes code more readable and self-documenting.

Numeric Enums

By default, Enums assign numerical values starting from 0:

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

let playerHeading: Direction = Direction.Up;

String Enums

In string enums, each member must be explicitly initialized with a string literal. String enums are easier to debug because the value printed at runtime matches the member name.

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

let currentStatus: OrderStatus = OrderStatus.Pending;

2. The Cost of Enums: Runtime Objects

Unlike most TypeScript features which disappear after compilation, Enums compile into real JavaScript objects.

For example, our Direction enum compiles into this JavaScript code:

var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Down"] = 1] = "Down";
    Direction[Direction["Left"] = 2] = "Left";
    Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));

Optimization: const Enums

To avoid the runtime overhead of normal enums, you can use const enums. These are completely removed by the compiler, and their usages are replaced by inline values.

const enum APIEndpoint {
  Users = "/users",
  Posts = "/posts"
}

// Compiles directly to: console.log("/users");
console.log(APIEndpoint.Users);

3. Literal Types: The Modern Alternative

Literal types allow you to specify exact values that a variable can hold. They are usually combined with Union types.

type TrafficLight = "Red" | "Yellow" | "Green";

let activeLight: TrafficLight = "Red";

// This will trigger a compiler error:
// activeLight = "Blue";

Objects and const Assertions

When you define a standard configuration object, TypeScript assumes its properties might change, so it widens the types (e.g., "Red" becomes string).

You can prevent this by using a as const assertion:

const Config = {
  theme: "dark",
  version: 1.0
} as const;

// Config.theme is now typed as the literal "dark" rather than string.

4. Enum vs. Union of Literals

Here is a quick comparison to help you choose:

  1. Use Literal Unions by default in modern frontend projects. They compile to nothing, are easy to read, and integrate perfectly with standard JavaScript APIs.
  2. Use Enums when you need to perform reverse mappings (numeric enums), when you want strict runtime namespace safety, or when building large backend applications.

5. Summary

  • Numeric enums start at zero and auto-increment, while string enums use explicit values.
  • Enums generate runtime JavaScript code unless you use const enum.
  • Literal types restrict variables to specific strings, numbers, or booleans.
  • Combine literal types with union operators for clean, zero-overhead type constraints.
Published on Last updated: