← run

ts-05-state-machine

1.000
7/7 tests· typing

Proposed solution

```ts
export interface Machine<S extends string, E extends string> {
  state: S;
  send(event: E): void;
  can(event: E): boolean;
}

export function createMachine<S extends string, E extends string>(config: {
  initial: S;
  states: Record<S, Partial<Record<E, S>>>;
}): Machine<S, E> {
  let currentState = config.initial;
  
  return {
    get state() {
      return currentState;
    },
    
    send(event) {
      const stateTransitions = config.states[currentState];
      const nextState = stateTransitions?.[event];
      
      if (nextState !== undefined) {
        currentState = nextState;
      }
    },
    
    can(event) {
      const stateTransitions = config.states[currentState];
      return stateTransitions?.[event] !== undefined;
    }
  };
}
```

Test output (stdout)

TAP version 13
# Subtest: starts in the initial state
ok 1 - starts in the initial state
  ---
  duration_ms: 0.361162
  type: 'test'
  ...
# Subtest: valid transition changes state
ok 2 - valid transition changes state
  ---
  duration_ms: 0.06719
  type: 'test'
  ...
# Subtest: invalid transition is ignored
ok 3 - invalid transition is ignored
  ---
  duration_ms: 0.04297
  type: 'test'
  ...
# Subtest: can reflects available transitions
ok 4 - can reflects available transitions
  ---
  duration_ms: 0.042561
  type: 'test'
  ...
# Subtest: can updates after a transition
ok 5 - can updates after a transition
  ---
  duration_ms: 0.04481
  type: 'test'
  ...
# Subtest: multi-step sequence
ok 6 - multi-step sequence
  ---
  duration_ms: 0.03826
  type: 'test'
  ...
# Subtest: self / terminal states with no outgoing events ignore everything
ok 7 - self / terminal states with no outgoing events ignore everything
  ---
  duration_ms: 0.425863
  type: 'test'
  ...
1..7
# tests 7
# suites 0
# pass 7
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 76.895492
System prompt
You are an expert programmer. Solve the task exactly as specified. Output your solution as fenced code blocks using the required file name(s) and the exact function/type signatures requested. Prefer correctness; do not include prose outside code unless asked.