or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions.mdactors.mdgraph-utilities.mdguards.mdindex.mdstate-machines.md

state-machines.mddocs/

0

# State Machines

1

2

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.

3

4

## Capabilities

5

6

### Machine Creation

7

8

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

9

10

```typescript { .api }

11

/**

12

* Creates a state machine definition from configuration

13

* @param config - Machine configuration with states, transitions, context, and behavior

14

* @returns StateMachine instance that can be used to create actors

15

*/

16

function createMachine<

17

TContext = any,

18

TEvent extends EventObject = EventObject,

19

TActor = any,

20

TAction = any,

21

TGuard = any,

22

TDelay = string,

23

TTag = string,

24

TInput = any,

25

TOutput = any

26

>(

27

config: MachineConfig<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag, TInput, TOutput>

28

): StateMachine<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag, TInput, TOutput>;

29

30

interface MachineConfig<

31

TContext = any,

32

TEvent extends EventObject = EventObject,

33

TActor = any,

34

TAction = any,

35

TGuard = any,

36

TDelay = string,

37

TTag = string,

38

TInput = any,

39

TOutput = any

40

> {

41

/** Unique identifier for the machine */

42

id?: string;

43

/** Initial state or initial transition configuration */

44

initial?: string | InitialTransitionConfig<TContext, TEvent>;

45

/** Initial context data or factory function */

46

context?: TContext | ContextFactory<TContext, TEvent>;

47

/** Map of state names to state configurations */

48

states?: StatesConfig<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>;

49

/** Event transitions at the machine level */

50

on?: TransitionsConfig<TContext, TEvent, TAction, TGuard, TDelay>;

51

/** Actions to execute when entering the machine */

52

entry?: Actions<TContext, TEvent, TAction>;

53

/** Actions to execute when exiting the machine */

54

exit?: Actions<TContext, TEvent, TAction>;

55

/** Delayed transitions (after events) */

56

after?: DelayedTransitions<TContext, TEvent, TAction, TGuard, TDelay>;

57

/** Always-triggered transitions (eventless transitions) */

58

always?: TransitionConfigOrTarget<TContext, TEvent, TAction, TGuard>[];

59

/** Actor invocations */

60

invoke?: InvokeConfig<TContext, TEvent, TActor>[];

61

/** Transitions triggered when machine completes */

62

onDone?: TransitionConfigOrTarget<TContext, DoneStateEvent<TOutput>, TAction, TGuard>[];

63

/** Tags for state identification */

64

tags?: TTag[];

65

/** Human-readable description */

66

description?: string;

67

/** Machine type */

68

type?: "atomic" | "compound" | "parallel" | "final" | "history";

69

/** Output value or mapper function */

70

output?: Mapper<TContext, TEvent, TOutput> | TOutput;

71

/** Metadata object */

72

meta?: MetaObject;

73

}

74

```

75

76

**Usage Examples:**

77

78

```typescript

79

import { createMachine } from "xstate";

80

81

// Simple toggle machine

82

const toggleMachine = createMachine({

83

id: "toggle",

84

initial: "inactive",

85

states: {

86

inactive: {

87

on: { TOGGLE: "active" }

88

},

89

active: {

90

on: { TOGGLE: "inactive" }

91

}

92

}

93

});

94

95

// Machine with context and actions

96

const counterMachine = createMachine({

97

id: "counter",

98

initial: "idle",

99

context: { count: 0 },

100

states: {

101

idle: {

102

on: {

103

INCREMENT: {

104

actions: assign({ count: ({ context }) => context.count + 1 })

105

},

106

DECREMENT: {

107

actions: assign({ count: ({ context }) => context.count - 1 })

108

}

109

}

110

}

111

}

112

});

113

```

114

115

### Setup Function

116

117

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

118

119

```typescript { .api }

120

/**

121

* Creates a machine factory with predefined implementations

122

* @param implementations - Object containing actions, guards, actors, delays implementations

123

* @returns Object with createMachine function using the provided implementations

124

*/

125

function setup<T extends SetupTypes>(

126

implementations: T

127

): {

128

createMachine<TConfig extends MachineConfig<any, any>>(

129

config: TConfig

130

): StateMachine</* resolved type parameters */>;

131

};

132

133

interface SetupTypes {

134

types?: {

135

context?: any;

136

events?: { type: string };

137

input?: any;

138

output?: any;

139

actions?: { type: string };

140

guards?: { type: string };

141

delays?: string;

142

tags?: string;

143

actors?: { type: string };

144

};

145

actions?: Record<string, ActionFunction<any, any>>;

146

guards?: Record<string, GuardPredicate<any, any>>;

147

actors?: Record<string, AnyActorLogic>;

148

delays?: Record<string, DelayConfig<any, any>>;

149

}

150

```

151

152

**Usage Examples:**

153

154

```typescript

155

import { setup, assign } from "xstate";

156

157

// Setup with implementations

158

const { createMachine } = setup({

159

types: {

160

context: {} as { count: number },

161

events: {} as { type: "INCREMENT" } | { type: "DECREMENT" } | { type: "RESET" }

162

},

163

actions: {

164

increment: assign({ count: ({ context }) => context.count + 1 }),

165

decrement: assign({ count: ({ context }) => context.count - 1 }),

166

reset: assign({ count: 0 })

167

},

168

guards: {

169

isPositive: ({ context }) => context.count > 0

170

}

171

});

172

173

// Create machine using setup

174

const machine = createMachine({

175

initial: "active",

176

context: { count: 0 },

177

states: {

178

active: {

179

on: {

180

INCREMENT: { actions: "increment" },

181

DECREMENT: {

182

guard: "isPositive",

183

actions: "decrement"

184

},

185

RESET: { actions: "reset" }

186

}

187

}

188

}

189

});

190

```

191

192

### State Node

193

194

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

195

196

```typescript { .api }

197

class StateNode<

198

TContext = any,

199

TEvent extends EventObject = EventObject

200

> {

201

/** State node identifier */

202

readonly id: string;

203

/** State node key within parent */

204

readonly key: string;

205

/** State node type */

206

readonly type: "atomic" | "compound" | "parallel" | "final" | "history";

207

/** Parent state node */

208

readonly parent?: StateNode<TContext, TEvent>;

209

/** Child state nodes */

210

readonly states: Record<string, StateNode<TContext, TEvent>>;

211

/** Entry actions */

212

readonly entry: ActionFunction<TContext, TEvent>[];

213

/** Exit actions */

214

readonly exit: ActionFunction<TContext, TEvent>[];

215

/** Event transitions */

216

readonly on: TransitionDefinitionMap<TContext, TEvent>;

217

/** Always transitions */

218

readonly always: TransitionDefinition<TContext, TEvent>[];

219

/** Delayed transitions */

220

readonly after: DelayedTransitionDefinition<TContext, TEvent>[];

221

/** Invocations */

222

readonly invoke: InvokeDefinition<TContext, TEvent>[];

223

/** Tags */

224

readonly tags: string[];

225

/** Description */

226

readonly description?: string;

227

/** Metadata */

228

readonly meta: MetaObject;

229

230

/** Gets all state nodes recursively */

231

getStateNodes(): StateNode<TContext, TEvent>[];

232

/** Gets state node by relative key */

233

getStateNode(stateKey: string): StateNode<TContext, TEvent>;

234

/** Gets initial state node */

235

getInitialStateNode(): StateNode<TContext, TEvent>;

236

}

237

```

238

239

### StateMachine Class

240

241

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

242

243

```typescript { .api }

244

class StateMachine<

245

TContext = any,

246

TEvent extends EventObject = EventObject,

247

TActor = any,

248

TAction = any,

249

TGuard = any,

250

TDelay = string,

251

TTag = string,

252

TInput = any,

253

TOutput = any

254

> extends StateNode<TContext, TEvent> {

255

/** Machine configuration */

256

readonly config: MachineConfig<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag, TInput, TOutput>;

257

/** Machine implementations */

258

readonly implementations: MachineImplementations<TContext, TEvent, TActor, TAction, TGuard, TDelay>;

259

/** Machine options */

260

readonly options: MachineOptions<TContext, TEvent, TActor, TAction, TGuard, TDelay>;

261

262

/**

263

* Gets the initial snapshot for the machine

264

* @param input - Input data for initial context

265

* @returns Initial machine snapshot

266

*/

267

getInitialSnapshot(

268

input?: TInput

269

): MachineSnapshot<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>;

270

271

/**

272

* Computes the next snapshot given current snapshot and event

273

* @param snapshot - Current machine snapshot

274

* @param event - Event to process

275

* @returns Next machine snapshot

276

*/

277

transition(

278

snapshot: MachineSnapshot<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>,

279

event: TEvent

280

): MachineSnapshot<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>;

281

282

/**

283

* Gets state node by state ID

284

* @param stateId - State identifier

285

* @returns State node with the given ID

286

*/

287

getStateNodeById(stateId: string): StateNode<TContext, TEvent>;

288

289

/**

290

* Gets all state nodes matching the given state value

291

* @param stateValue - State value to match

292

* @returns Array of matching state nodes

293

*/

294

getStateNodeByPath(stateValue: StateValue): StateNode<TContext, TEvent>[];

295

296

/**

297

* Resolves a state value to state nodes

298

* @param stateValue - State value to resolve

299

* @returns Array of resolved state nodes

300

*/

301

resolveStateValue(stateValue: StateValue): StateNode<TContext, TEvent>[];

302

}

303

```

304

305

### Snapshot Operations

306

307

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

308

309

```typescript { .api }

310

/**

311

* Gets the initial snapshot from actor logic

312

* @param actorLogic - Actor logic to get initial snapshot from

313

* @param input - Optional input for initial snapshot

314

* @returns Initial snapshot

315

*/

316

function getInitialSnapshot<TLogic extends AnyActorLogic>(

317

actorLogic: TLogic,

318

input?: InputFrom<TLogic>

319

): SnapshotFrom<TLogic>;

320

321

/**

322

* Computes the next snapshot given current snapshot and event

323

* @param actorLogic - Actor logic to use for computation

324

* @param snapshot - Current snapshot

325

* @param event - Event to process

326

* @returns Next snapshot

327

*/

328

function getNextSnapshot<TLogic extends AnyActorLogic>(

329

actorLogic: TLogic,

330

snapshot: SnapshotFrom<TLogic>,

331

event: EventFromLogic<TLogic>

332

): SnapshotFrom<TLogic>;

333

334

/**

335

* Type guard to check if snapshot is a machine snapshot

336

* @param snapshot - Snapshot to check

337

* @returns True if snapshot is a machine snapshot

338

*/

339

function isMachineSnapshot(

340

snapshot: Snapshot<unknown>

341

): snapshot is AnyMachineSnapshot;

342

```

343

344

### Transition Functions

345

346

Low-level transition computation functions for advanced use cases.

347

348

```typescript { .api }

349

/**

350

* Creates a transition from state and event

351

* @param machine - State machine

352

* @param stateValue - Current state value

353

* @param context - Current context

354

* @param event - Event to process

355

* @returns Transition result

356

*/

357

function transition<TContext, TEvent extends EventObject>(

358

machine: StateMachine<TContext, TEvent>,

359

stateValue: StateValue,

360

context: TContext,

361

event: TEvent

362

): MachineSnapshot<TContext, TEvent>;

363

364

/**

365

* Creates initial transition for a machine

366

* @param machine - State machine

367

* @param input - Optional input data

368

* @returns Initial transition result

369

*/

370

function initialTransition<TContext, TEvent extends EventObject>(

371

machine: StateMachine<TContext, TEvent>,

372

input?: any

373

): MachineSnapshot<TContext, TEvent>;

374

```

375

376

### Utility Functions

377

378

Additional utility functions for working with states and events.

379

380

```typescript { .api }

381

/**

382

* Type-safe event assertion function

383

* @param event - Event to assert type for

384

* @param eventType - Expected event type

385

*/

386

function assertEvent<TEvent extends EventObject, TEventType extends TEvent["type"]>(

387

event: TEvent,

388

eventType: TEventType

389

): asserts event is Extract<TEvent, { type: TEventType }>;

390

391

/**

392

* Checks if a state value matches the current state

393

* @param state - State to check against

394

* @param stateValue - State value to match

395

* @returns True if state matches the state value

396

*/

397

function matchesState(state: any, stateValue: StateValue): boolean;

398

399

/**

400

* Converts a state path array to a state value

401

* @param statePath - Array of state keys representing path

402

* @returns State value object from path

403

*/

404

function pathToStateValue(statePath: string[]): StateValue;

405

406

/**

407

* Converts observer-like objects to proper observer objects

408

* @param observer - Observer function or object

409

* @returns Standardized observer object

410

*/

411

function toObserver<T>(

412

observer: Observer<T> | ((value: T) => void)

413

): Observer<T>;

414

```

415

416

### Development and Testing Tools

417

418

Tools for development, debugging, and testing state machines.

419

420

```typescript { .api }

421

/**

422

* Simulated clock for controlling time in tests and simulations

423

*/

424

class SimulatedClock {

425

/** Current simulated time */

426

now(): number;

427

428

/** Set the current time */

429

set(time: number): void;

430

431

/** Advance time by the specified amount */

432

increment(time: number): void;

433

434

/** Start the clock */

435

start(): void;

436

437

/** Stop the clock */

438

stop(): void;

439

440

/** Schedule a timeout */

441

setTimeout(fn: () => void, timeout: number): number;

442

443

/** Clear a scheduled timeout */

444

clearTimeout(id: number): void;

445

446

/** Schedule an interval */

447

setInterval(fn: () => void, interval: number): number;

448

449

/** Clear a scheduled interval */

450

clearInterval(id: number): void;

451

}

452

```

453

454

## Configuration Types

455

456

```typescript { .api }

457

interface StateNodeConfig<

458

TContext = any,

459

TEvent extends EventObject = EventObject,

460

TActor = any,

461

TAction = any,

462

TGuard = any,

463

TDelay = string,

464

TTag = string

465

> {

466

id?: string;

467

type?: "atomic" | "compound" | "parallel" | "final" | "history";

468

initial?: string | InitialTransitionConfig<TContext, TEvent>;

469

entry?: Actions<TContext, TEvent, TAction>;

470

exit?: Actions<TContext, TEvent, TAction>;

471

on?: TransitionsConfig<TContext, TEvent, TAction, TGuard, TDelay>;

472

after?: DelayedTransitions<TContext, TEvent, TAction, TGuard, TDelay>;

473

always?: TransitionConfigOrTarget<TContext, TEvent, TAction, TGuard>[];

474

invoke?: InvokeConfig<TContext, TEvent, TActor>[];

475

states?: StatesConfig<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>;

476

onDone?: TransitionConfigOrTarget<TContext, DoneStateEvent<unknown>, TAction, TGuard>[];

477

tags?: TTag[];

478

description?: string;

479

meta?: MetaObject;

480

}

481

482

interface TransitionConfig<

483

TContext = any,

484

TEvent extends EventObject = EventObject,

485

TAction = any,

486

TGuard = any,

487

TDelay = string

488

> {

489

target?: string | string[];

490

actions?: Actions<TContext, TEvent, TAction>;

491

guard?: Guard<TContext, TEvent, any, any>;

492

reenter?: boolean;

493

description?: string;

494

meta?: MetaObject;

495

}

496

497

type StatesConfig<

498

TContext = any,

499

TEvent extends EventObject = EventObject,

500

TActor = any,

501

TAction = any,

502

TGuard = any,

503

TDelay = string,

504

TTag = string

505

> = {

506

[K in string]: StateNodeConfig<TContext, TEvent, TActor, TAction, TGuard, TDelay, TTag>;

507

};

508

509

type TransitionsConfig<

510

TContext = any,

511

TEvent extends EventObject = EventObject,

512

TAction = any,

513

TGuard = any,

514

TDelay = string

515

> = {

516

[K in TEvent["type"]]?: TransitionConfigOrTarget<TContext, Extract<TEvent, { type: K }>, TAction, TGuard>[];

517

};

518

```