State Pattern - State Machines in TypeScript

Learn the State pattern for implementing state machines. TypeScript examples for order processing, UI workflows, game logic, and connection management.

Behavioral

Detailed Explanation

State Pattern

The State pattern allows an object to alter its behavior when its internal state changes. The object appears to change its class. It is the object-oriented implementation of a finite state machine.

Problem: Conditional Explosion

Without State, objects with multiple states accumulate massive switch statements:

// Before: grows with every new state
class Order {
  process() {
    switch (this.status) {
      case "pending": /* ... */ break;
      case "paid": /* ... */ break;
      case "shipped": /* ... */ break;
      case "delivered": /* ... */ break;
      case "cancelled": /* ... */ break;
    }
  }
}

State Pattern Solution

Each state becomes its own class:

interface OrderState {
  process(order: Order): void;
  cancel(order: Order): void;
  name: string;
}

class PendingState implements OrderState {
  name = "Pending";
  process(order: Order) {
    // validate payment, transition to PaidState
    order.setState(new PaidState());
  }
  cancel(order: Order) {
    order.setState(new CancelledState());
  }
}

Transition Rules

State transitions are defined within state classes themselves. Each state knows which states it can transition to, encapsulating the transition rules close to where they matter. This makes it easy to add new states without modifying existing ones.

State vs Strategy

Both patterns use composition. The critical difference: State transitions happen automatically based on internal conditions. Strategy is explicitly set by the client. A traffic light changes state on its own; a compression algorithm is chosen by the user.

Modern Alternatives

Libraries like XState provide a declarative way to define state machines in JavaScript/TypeScript with visualizers, guards, and side effects. For complex state machines, a dedicated library may be more maintainable than hand-coded State pattern.

Use Case

State is ideal for order processing workflows (pending, paid, shipped, delivered), TCP connection states (listen, established, closed), game character behavior (idle, walking, attacking), UI wizard steps, and any system with well-defined states and transitions.

Try It — Design Pattern Reference

Open full tool