Typed State Machine Transitions

Model states and allowed transitions as types so invalid transitions are rejected by the compiler and the reducer stays exhaustive.

TypescriptResilience

Code

snippet
type State =
  | { value: "idle" }
  | { value: "loading"; startedAt: number }
  | { value: "ready"; data: string[] }
  | { value: "failed"; error: string };

type Event =
  | { type: "fetch" }
  | { type: "resolve"; data: string[] }
  | { type: "reject"; error: string }
  | { type: "reset" };

export function reduce(state: State, event: Event): State {
  switch (state.value) {
    case "idle":
      return event.type === "fetch" ? { value: "loading", startedAt: Date.now() } : state;
    case "loading":
      if (event.type === "resolve") return { value: "ready", data: event.data };
      if (event.type === "reject") return { value: "failed", error: event.error };
      return state;
    case "ready":
    case "failed":
      return event.type === "reset" ? { value: "idle" } : state;
  }
}