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
```