TypeScript: a process lifecycle as a typed state machine

An operating system tracks each process through states. A new process becomes ready, the scheduler dispatches it to running, a running process may be preempted back to ready, blocked on I/O in the waiting state, or finish as terminated. A waiting process becomes ready again when its I/O completes, but it cannot jump straight to running.

TypeScript
type State = "new" | "ready" | "running" | "waiting" | "terminated";

const transitions: Record<State, State[]> = {
  new: ["ready"],
  ready: ["running"],
  running: ["ready", "waiting", "terminated"],
  waiting: ["ready"],
  terminated: [],
};

function move(from: State, to: State): State {
  if (!transitions[from].includes(to)) {
    throw new Error("illegal transition: " + from + " -> " + to);
  }
  return to;
}

let state: State = "new";
for (const next of ["ready", "running", "waiting", "ready", "running", "terminated"] as State[]) {
  const before = state;
  state = move(state, next);
  console.log(before + " -> " + state);
}

try {
  move("waiting", "running");
} catch (error) {
  console.log((error as Error).message);
}
Read the full lesson