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.
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.