CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-xstate

Actor-based state management & orchestration for complex app logic.

Overview
Eval results
Files

state-machines.mddocs/

State Machines

Core functionality for creating and configuring finite state machines and statecharts with states, transitions, guards, and actions. State machines provide predictable and visual ways to model complex application logic.

Capabilities

Machine Creation

Creates a state machine definition from configuration with states, transitions, context, and behavior.

/**
 * Creates a state machine definition from configuration
 * @param config - Machine configuration with states, transitions, context, and behavior
 * @returns StateMachine instance that can be used to create actors
 */
function createMachine<
  TContext = any,
  TEvent extends EventObject = EventObject,
  TActor = any,
  TAction = any,
  TGuard = any,
  TDelay = string,
  TTag = string,
  TInput = any,
  TOutput = any
>(
  config: MachineConfig<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag, TInput, TOutput>
): StateMachine<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag, TInput, TOutput>;

interface MachineConfig<
  TContext = any,
  TEvent extends EventObject = EventObject,
  TActor = any,
  TAction = any,
  TGuard = any,
  TDelay = string,
  TTag = string,
  TInput = any,
  TOutput = any
> {
  /** Unique identifier for the machine */
  id?: string;
  /** Initial state or initial transition configuration */
  initial?: string | InitialTransitionConfig<TContext, TEvent>;
  /** Initial context data or factory function */
  context?: TContext | ContextFactory<TContext, TEvent>;
  /** Map of state names to state configurations */
  states?: StatesConfig<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>;
  /** Event transitions at the machine level */
  on?: TransitionsConfig<TContext, TEvent, TAction, TGuard, TDelay>;
  /** Actions to execute when entering the machine */
  entry?: Actions<TContext, TEvent, TAction>;
  /** Actions to execute when exiting the machine */
  exit?: Actions<TContext, TEvent, TAction>;
  /** Delayed transitions (after events) */
  after?: DelayedTransitions<TContext, TEvent, TAction, TGuard, TDelay>;
  /** Always-triggered transitions (eventless transitions) */
  always?: TransitionConfigOrTarget<TContext, TEvent, TAction, TGuard>[];
  /** Actor invocations */
  invoke?: InvokeConfig<TContext, TEvent, TActor>[];
  /** Transitions triggered when machine completes */
  onDone?: TransitionConfigOrTarget<TContext, DoneStateEvent<TOutput>, TAction, TGuard>[];
  /** Tags for state identification */
  tags?: TTag[];
  /** Human-readable description */
  description?: string;
  /** Machine type */
  type?: "atomic" | "compound" | "parallel" | "final" | "history";
  /** Output value or mapper function */
  output?: Mapper<TContext, TEvent, TOutput> | TOutput;
  /** Metadata object */
  meta?: MetaObject;
}

Usage Examples:

import { createMachine } from "xstate";

// Simple toggle machine
const toggleMachine = createMachine({
  id: "toggle",
  initial: "inactive",
  states: {
    inactive: {
      on: { TOGGLE: "active" }
    },
    active: {
      on: { TOGGLE: "inactive" }
    }
  }
});

// Machine with context and actions
const counterMachine = createMachine({
  id: "counter",
  initial: "idle",
  context: { count: 0 },
  states: {
    idle: {
      on: {
        INCREMENT: {
          actions: assign({ count: ({ context }) => context.count + 1 })
        },
        DECREMENT: {
          actions: assign({ count: ({ context }) => context.count - 1 })
        }
      }
    }
  }
});

Setup Function

Creates a machine factory with predefined implementations for type-safe machine creation.

/**
 * Creates a machine factory with predefined implementations
 * @param implementations - Object containing actions, guards, actors, delays implementations
 * @returns Object with createMachine function using the provided implementations
 */
function setup<T extends SetupTypes>(
  implementations: T
): {
  createMachine<TConfig extends MachineConfig<any, any>>(
    config: TConfig
  ): StateMachine</* resolved type parameters */>;
};

interface SetupTypes {
  types?: {
    context?: any;
    events?: { type: string };
    input?: any;
    output?: any;
    actions?: { type: string };
    guards?: { type: string };
    delays?: string;
    tags?: string;
    actors?: { type: string };
  };
  actions?: Record<string, ActionFunction<any, any>>;
  guards?: Record<string, GuardPredicate<any, any>>;
  actors?: Record<string, AnyActorLogic>;
  delays?: Record<string, DelayConfig<any, any>>;
}

Usage Examples:

import { setup, assign } from "xstate";

// Setup with implementations
const { createMachine } = setup({
  types: {
    context: {} as { count: number },
    events: {} as { type: "INCREMENT" } | { type: "DECREMENT" } | { type: "RESET" }
  },
  actions: {
    increment: assign({ count: ({ context }) => context.count + 1 }),
    decrement: assign({ count: ({ context }) => context.count - 1 }),
    reset: assign({ count: 0 })
  },
  guards: {
    isPositive: ({ context }) => context.count > 0
  }
});

// Create machine using setup
const machine = createMachine({
  initial: "active",
  context: { count: 0 },
  states: {
    active: {
      on: {
        INCREMENT: { actions: "increment" },
        DECREMENT: { 
          guard: "isPositive",
          actions: "decrement" 
        },
        RESET: { actions: "reset" }
      }
    }
  }
});

State Node

Individual state node implementation providing state-specific behavior and hierarchy.

class StateNode<
  TContext = any,
  TEvent extends EventObject = EventObject
> {
  /** State node identifier */
  readonly id: string;
  /** State node key within parent */
  readonly key: string;
  /** State node type */
  readonly type: "atomic" | "compound" | "parallel" | "final" | "history";
  /** Parent state node */
  readonly parent?: StateNode<TContext, TEvent>;
  /** Child state nodes */
  readonly states: Record<string, StateNode<TContext, TEvent>>;
  /** Entry actions */
  readonly entry: ActionFunction<TContext, TEvent>[];
  /** Exit actions */
  readonly exit: ActionFunction<TContext, TEvent>[];
  /** Event transitions */
  readonly on: TransitionDefinitionMap<TContext, TEvent>;
  /** Always transitions */
  readonly always: TransitionDefinition<TContext, TEvent>[];
  /** Delayed transitions */  
  readonly after: DelayedTransitionDefinition<TContext, TEvent>[];
  /** Invocations */
  readonly invoke: InvokeDefinition<TContext, TEvent>[];
  /** Tags */
  readonly tags: string[];
  /** Description */
  readonly description?: string;
  /** Metadata */
  readonly meta: MetaObject;

  /** Gets all state nodes recursively */
  getStateNodes(): StateNode<TContext, TEvent>[];
  /** Gets state node by relative key */
  getStateNode(stateKey: string): StateNode<TContext, TEvent>;
  /** Gets initial state node */
  getInitialStateNode(): StateNode<TContext, TEvent>;
}

StateMachine Class

Complete state machine implementation with transition logic and actor creation capabilities.

class StateMachine<
  TContext = any,
  TEvent extends EventObject = EventObject,
  TActor = any,
  TAction = any,
  TGuard = any,
  TDelay = string,
  TTag = string,
  TInput = any,
  TOutput = any
> extends StateNode<TContext, TEvent> {
  /** Machine configuration */
  readonly config: MachineConfig<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag, TInput, TOutput>;
  /** Machine implementations */
  readonly implementations: MachineImplementations<TContext, TEvent, TActor, TAction, TGuard, TDelay>;
  /** Machine options */
  readonly options: MachineOptions<TContext, TEvent, TActor, TAction, TGuard, TDelay>;

  /**
   * Gets the initial snapshot for the machine
   * @param input - Input data for initial context
   * @returns Initial machine snapshot
   */
  getInitialSnapshot(
    input?: TInput
  ): MachineSnapshot<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>;

  /**
   * Computes the next snapshot given current snapshot and event
   * @param snapshot - Current machine snapshot
   * @param event - Event to process
   * @returns Next machine snapshot
   */
  transition(
    snapshot: MachineSnapshot<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>,
    event: TEvent
  ): MachineSnapshot<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>;

  /**
   * Gets state node by state ID
   * @param stateId - State identifier
   * @returns State node with the given ID
   */
  getStateNodeById(stateId: string): StateNode<TContext, TEvent>;

  /**
   * Gets all state nodes matching the given state value
   * @param stateValue - State value to match
   * @returns Array of matching state nodes
   */
  getStateNodeByPath(stateValue: StateValue): StateNode<TContext, TEvent>[];

  /**
   * Resolves a state value to state nodes
   * @param stateValue - State value to resolve
   * @returns Array of resolved state nodes
   */
  resolveStateValue(stateValue: StateValue): StateNode<TContext, TEvent>[];
}

Snapshot Operations

Utility functions for working with machine snapshots and computing state transitions.

/**
 * Gets the initial snapshot from actor logic
 * @param actorLogic - Actor logic to get initial snapshot from
 * @param input - Optional input for initial snapshot
 * @returns Initial snapshot
 */
function getInitialSnapshot<TLogic extends AnyActorLogic>(
  actorLogic: TLogic,
  input?: InputFrom<TLogic>
): SnapshotFrom<TLogic>;

/**
 * Computes the next snapshot given current snapshot and event
 * @param actorLogic - Actor logic to use for computation
 * @param snapshot - Current snapshot
 * @param event - Event to process
 * @returns Next snapshot
 */
function getNextSnapshot<TLogic extends AnyActorLogic>(
  actorLogic: TLogic,
  snapshot: SnapshotFrom<TLogic>,
  event: EventFromLogic<TLogic>
): SnapshotFrom<TLogic>;

/**
 * Type guard to check if snapshot is a machine snapshot
 * @param snapshot - Snapshot to check
 * @returns True if snapshot is a machine snapshot
 */
function isMachineSnapshot(
  snapshot: Snapshot<unknown>
): snapshot is AnyMachineSnapshot;

Transition Functions

Low-level transition computation functions for advanced use cases.

/**
 * Creates a transition from state and event
 * @param machine - State machine
 * @param stateValue - Current state value
 * @param context - Current context
 * @param event - Event to process
 * @returns Transition result
 */
function transition<TContext, TEvent extends EventObject>(
  machine: StateMachine<TContext, TEvent>,
  stateValue: StateValue,
  context: TContext,
  event: TEvent
): MachineSnapshot<TContext, TEvent>;

/**
 * Creates initial transition for a machine
 * @param machine - State machine
 * @param input - Optional input data
 * @returns Initial transition result
 */
function initialTransition<TContext, TEvent extends EventObject>(
  machine: StateMachine<TContext, TEvent>,
  input?: any
): MachineSnapshot<TContext, TEvent>;

Utility Functions

Additional utility functions for working with states and events.

/**
 * Type-safe event assertion function
 * @param event - Event to assert type for
 * @param eventType - Expected event type
 */
function assertEvent<TEvent extends EventObject, TEventType extends TEvent["type"]>(
  event: TEvent,
  eventType: TEventType
): asserts event is Extract<TEvent, { type: TEventType }>;

/**
 * Checks if a state value matches the current state
 * @param state - State to check against
 * @param stateValue - State value to match
 * @returns True if state matches the state value
 */
function matchesState(state: any, stateValue: StateValue): boolean;

/**
 * Converts a state path array to a state value
 * @param statePath - Array of state keys representing path
 * @returns State value object from path
 */
function pathToStateValue(statePath: string[]): StateValue;

/**
 * Converts observer-like objects to proper observer objects
 * @param observer - Observer function or object
 * @returns Standardized observer object
 */
function toObserver<T>(
  observer: Observer<T> | ((value: T) => void)
): Observer<T>;

Development and Testing Tools

Tools for development, debugging, and testing state machines.

/**
 * Simulated clock for controlling time in tests and simulations
 */
class SimulatedClock {
  /** Current simulated time */
  now(): number;
  
  /** Set the current time */
  set(time: number): void;
  
  /** Advance time by the specified amount */
  increment(time: number): void;
  
  /** Start the clock */
  start(): void;
  
  /** Stop the clock */
  stop(): void;
  
  /** Schedule a timeout */
  setTimeout(fn: () => void, timeout: number): number;
  
  /** Clear a scheduled timeout */
  clearTimeout(id: number): void;
  
  /** Schedule an interval */
  setInterval(fn: () => void, interval: number): number;
  
  /** Clear a scheduled interval */
  clearInterval(id: number): void;
}

Configuration Types

interface StateNodeConfig<
  TContext = any,
  TEvent extends EventObject = EventObject,
  TActor = any,
  TAction = any,
  TGuard = any,
  TDelay = string,
  TTag = string
> {
  id?: string;
  type?: "atomic" | "compound" | "parallel" | "final" | "history";
  initial?: string | InitialTransitionConfig<TContext, TEvent>;
  entry?: Actions<TContext, TEvent, TAction>;
  exit?: Actions<TContext, TEvent, TAction>;
  on?: TransitionsConfig<TContext, TEvent, TAction, TGuard, TDelay>;
  after?: DelayedTransitions<TContext, TEvent, TAction, TGuard, TDelay>;
  always?: TransitionConfigOrTarget<TContext, TEvent, TAction, TGuard>[];
  invoke?: InvokeConfig<TContext, TEvent, TActor>[];
  states?: StatesConfig<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>;
  onDone?: TransitionConfigOrTarget<TContext, DoneStateEvent<unknown>, TAction, TGuard>[];
  tags?: TTag[];
  description?: string;
  meta?: MetaObject;
}

interface TransitionConfig<
  TContext = any,
  TEvent extends EventObject = EventObject,
  TAction = any,
  TGuard = any,
  TDelay = string
> {
  target?: string | string[];
  actions?: Actions<TContext, TEvent, TAction>;
  guard?: Guard<TContext, TEvent, any, any>;
  reenter?: boolean;
  description?: string;
  meta?: MetaObject;
}

type StatesConfig<
  TContext = any,
  TEvent extends EventObject = EventObject,
  TActor = any,
  TAction = any,
  TGuard = any,
  TDelay = string,
  TTag = string
> = {
  [K in string]: StateNodeConfig<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>;
};

type TransitionsConfig<
  TContext = any,
  TEvent extends EventObject = EventObject,
  TAction = any,
  TGuard = any,
  TDelay = string
> = {
  [K in TEvent["type"]]?: TransitionConfigOrTarget<TContext, Extract<TEvent, { type: K }>, TAction, TGuard>[];
};

Install with Tessl CLI

npx tessl i tessl/npm-xstate

docs

actions.md

actors.md

graph-utilities.md

guards.md

index.md

state-machines.md

tile.json