0
# Actors
1
2
Actor system for creating, managing, and communicating with stateful actors that run state machines and other logic. Actors encapsulate state and behavior, communicating through message passing in a predictable and isolated manner.
3
4
## Capabilities
5
6
### Actor Creation
7
8
Creates and manages actor instances from various types of actor logic including state machines and specialized actor types.
9
10
```typescript { .api }
11
/**
12
* Creates an actor instance from actor logic
13
* @param logic - Actor logic (state machine or other actor logic)
14
* @param options - Optional configuration for the actor
15
* @returns Actor instance that can be started, stopped, and communicated with
16
*/
17
function createActor<TLogic extends AnyActorLogic>(
18
logic: TLogic,
19
options?: ActorOptions<TLogic>
20
): Actor<TLogic>;
21
22
/**
23
* Legacy alias for createActor
24
* @deprecated Use createActor instead
25
*/
26
function interpret<TLogic extends AnyActorLogic>(
27
logic: TLogic,
28
options?: ActorOptions<TLogic>
29
): Actor<TLogic>;
30
31
interface ActorOptions<TLogic extends AnyActorLogic> {
32
/** Unique identifier for the actor */
33
id?: string;
34
/** System identifier for the actor */
35
systemId?: string;
36
/** Input data for the actor */
37
input?: InputFrom<TLogic>;
38
/** Parent actor reference */
39
parent?: AnyActorRef;
40
/** Synchronize snapshot with parent */
41
syncSnapshot?: boolean;
42
/** Actor system reference */
43
system?: AnyActorSystem;
44
/** Logger for the actor */
45
logger?: (msg: string) => void;
46
/** Inspection observer */
47
inspect?: Observer<InspectionEvent>;
48
/** DevTools adapter */
49
devTools?: DevToolsAdapter;
50
}
51
```
52
53
**Usage Examples:**
54
55
```typescript
56
import { createMachine, createActor } from "xstate";
57
58
// Create actor from state machine
59
const machine = createMachine({
60
initial: "idle",
61
states: {
62
idle: {
63
on: { START: "running" }
64
},
65
running: {
66
on: { STOP: "idle" }
67
}
68
}
69
});
70
71
const actor = createActor(machine, {
72
id: "my-actor",
73
input: { count: 0 }
74
});
75
76
// Start the actor
77
actor.start();
78
79
// Send events
80
actor.send({ type: "START" });
81
```
82
83
### Actor Class
84
85
Main actor implementation providing state management, event handling, and lifecycle control.
86
87
```typescript { .api }
88
class Actor<TLogic extends AnyActorLogic> implements ActorRef<SnapshotFrom<TLogic>, EventFromLogic<TLogic>> {
89
/** Unique actor identifier */
90
readonly id: string;
91
/** Actor logic */
92
readonly logic: TLogic;
93
/** Actor options */
94
readonly options: ActorOptions<TLogic>;
95
/** Actor status */
96
readonly status: "not-started" | "running" | "stopped" | "error";
97
98
/**
99
* Starts the actor and begins processing
100
*/
101
start(): this;
102
103
/**
104
* Stops the actor and cleans up resources
105
*/
106
stop(): this;
107
108
/**
109
* Sends an event to the actor
110
* @param event - Event to send
111
*/
112
send(event: EventFromLogic<TLogic>): void;
113
114
/**
115
* Gets the current snapshot
116
* @returns Current actor snapshot
117
*/
118
getSnapshot(): SnapshotFrom<TLogic>;
119
120
/**
121
* Gets persisted snapshot data
122
* @returns Persisted snapshot
123
*/
124
getPersistedSnapshot(): Snapshot<unknown>;
125
126
/**
127
* Subscribes to actor state changes
128
* @param observer - Observer function or object
129
* @returns Subscription object
130
*/
131
subscribe(observer: Observer<SnapshotFrom<TLogic>>): Subscription;
132
133
/**
134
* Subscribes to actor state changes with next/error/complete callbacks
135
* @param nextListener - Called on state changes
136
* @param errorListener - Called on errors
137
* @param completeListener - Called on completion
138
* @returns Subscription object
139
*/
140
subscribe(
141
nextListener: (snapshot: SnapshotFrom<TLogic>) => void,
142
errorListener?: (error: any) => void,
143
completeListener?: () => void
144
): Subscription;
145
}
146
```
147
148
### Actor References
149
150
Interface for communicating with actors, providing a stable API for message passing and observation.
151
152
```typescript { .api }
153
interface ActorRef<
154
TSnapshot extends Snapshot<unknown>,
155
TEvent extends EventObject
156
> {
157
/** Unique actor identifier */
158
readonly id: string;
159
160
/**
161
* Sends an event to the actor
162
* @param event - Event to send
163
*/
164
send(event: TEvent): void;
165
166
/**
167
* Subscribes to actor state changes
168
* @param observer - Observer function or object
169
* @returns Subscription object
170
*/
171
subscribe(observer: Observer<TSnapshot>): Subscription;
172
173
/**
174
* Gets the current snapshot
175
* @returns Current actor snapshot
176
*/
177
getSnapshot(): TSnapshot;
178
179
/**
180
* Gets persisted snapshot data
181
* @returns Persisted snapshot
182
*/
183
getPersistedSnapshot(): Snapshot<unknown>;
184
185
/** Symbol.observable implementation */
186
[Symbol.observable](): InteropObservable<TSnapshot>;
187
}
188
189
interface BaseActorRef<TEvent extends EventObject> {
190
readonly id: string;
191
send(event: TEvent): void;
192
}
193
194
type AnyActorRef = ActorRef<any, any>;
195
type AnyActor = Actor<any>;
196
```
197
198
### Callback Actors
199
200
Creates actors from callback functions for subscription-based or free-form logic with bidirectional communication.
201
202
```typescript { .api }
203
/**
204
* Creates callback actor logic for subscription-based or free-form logic
205
* @param callback - Function defining the actor's behavior with access to input, system, self, sendBack, receive, emit
206
* @returns CallbackActorLogic that can be used to create actors
207
*/
208
function fromCallback<
209
TEvent extends EventObject,
210
TSentEvent extends EventObject = AnyEventObject,
211
TInput = any,
212
TEmitted = any
213
>(
214
callback: CallbackLogicFunction<TEvent, TSentEvent, TInput, TEmitted>
215
): CallbackActorLogic<TEvent, TInput, TEmitted>;
216
217
type CallbackLogicFunction<
218
TEvent extends EventObject,
219
TSentEvent extends EventObject,
220
TInput,
221
TEmitted
222
> = (params: {
223
/** Input data provided to the actor */
224
input: TInput;
225
/** Actor system reference */
226
system: AnyActorSystem;
227
/** Reference to this actor */
228
self: CallbackActorRef<TEvent, TInput>;
229
/** Function to send events back to parent */
230
sendBack: (event: TSentEvent) => void;
231
/** Function to register event handler */
232
receive: (listener: (event: TEvent) => void) => void;
233
/** Function to emit events to external handlers */
234
emit: (event: TEmitted) => void;
235
}) => (() => void) | void;
236
237
type CallbackActorLogic<TEvent extends EventObject, TInput, TEmitted> =
238
ActorLogic<CallbackSnapshot<TInput>, TEvent, TInput, AnyEventObject, TEmitted>;
239
240
interface CallbackSnapshot<TInput> extends Snapshot<undefined> {
241
input: TInput;
242
}
243
244
type CallbackActorRef<TEvent extends EventObject, TInput> =
245
ActorRef<CallbackSnapshot<TInput>, TEvent>;
246
```
247
248
**Usage Examples:**
249
250
```typescript
251
import { fromCallback, createActor } from "xstate/actors";
252
253
// WebSocket callback actor
254
const websocketLogic = fromCallback(({ input, sendBack, receive, emit }) => {
255
const ws = new WebSocket(input.url);
256
257
ws.onopen = () => emit({ type: "connected" });
258
ws.onmessage = (event) => sendBack({ type: "MESSAGE", data: event.data });
259
ws.onerror = (error) => sendBack({ type: "ERROR", error });
260
261
receive((event) => {
262
if (event.type === "SEND") {
263
ws.send(event.data);
264
}
265
});
266
267
return () => ws.close();
268
});
269
270
const actor = createActor(websocketLogic, {
271
input: { url: "ws://localhost:8080" }
272
});
273
```
274
275
### Promise Actors
276
277
Creates actors from async functions that resolve to a single value.
278
279
```typescript { .api }
280
/**
281
* Creates promise actor logic from an async process
282
* @param promiseCreator - Async function that returns a promise
283
* @returns PromiseActorLogic that resolves/rejects and emits the result
284
*/
285
function fromPromise<TOutput, TInput = any, TEmitted = any>(
286
promiseCreator: (params: {
287
input: TInput;
288
system: AnyActorSystem;
289
self: PromiseActorRef<TOutput>;
290
signal: AbortSignal;
291
emit: (event: TEmitted) => void;
292
}) => PromiseLike<TOutput>
293
): PromiseActorLogic<TOutput, TInput, TEmitted>;
294
295
type PromiseActorLogic<TOutput, TInput, TEmitted> =
296
ActorLogic<PromiseSnapshot<TOutput, TInput>, AnyEventObject, TInput, AnyEventObject, TEmitted>;
297
298
interface PromiseSnapshot<TOutput, TInput> extends Snapshot<TOutput> {
299
input: TInput;
300
}
301
302
type PromiseActorRef<TOutput> = ActorRef<PromiseSnapshot<TOutput, any>, AnyEventObject>;
303
```
304
305
**Usage Examples:**
306
307
```typescript
308
import { fromPromise, createActor } from "xstate/actors";
309
310
// Fetch data promise actor
311
const fetchUserLogic = fromPromise(async ({ input, signal, emit }) => {
312
emit({ type: "FETCH_START" });
313
314
const response = await fetch(`/api/users/${input.userId}`, {
315
signal
316
});
317
318
if (!response.ok) {
319
throw new Error(`Failed to fetch user: ${response.status}`);
320
}
321
322
const user = await response.json();
323
emit({ type: "FETCH_SUCCESS", user });
324
325
return user;
326
});
327
328
const actor = createActor(fetchUserLogic, {
329
input: { userId: "123" }
330
});
331
```
332
333
### Observable Actors
334
335
Creates actors from observable streams for reactive programming patterns.
336
337
```typescript { .api }
338
/**
339
* Creates observable actor logic from an observable stream
340
* @param observableCreator - Function that creates a subscribable stream
341
* @returns ObservableActorLogic that emits values from the stream
342
*/
343
function fromObservable<TContext, TInput = any, TEmitted = any>(
344
observableCreator: (params: {
345
input: TInput;
346
system: AnyActorSystem;
347
self: ObservableActorRef<TContext>;
348
emit: (event: TEmitted) => void;
349
}) => Subscribable<TContext>
350
): ObservableActorLogic<TContext, TInput, TEmitted>;
351
352
/**
353
* Creates event observable actor logic that sends events to parent
354
* @param lazyObservable - Function that creates a subscribable event stream
355
* @returns ObservableActorLogic that forwards events to parent
356
*/
357
function fromEventObservable<TEvent extends EventObject, TInput = any, TEmitted = any>(
358
lazyObservable: (params: {
359
input: TInput;
360
system: AnyActorSystem;
361
self: ObservableActorRef<TEvent>;
362
emit: (event: TEmitted) => void;
363
}) => Subscribable<TEvent>
364
): ObservableActorLogic<TEvent, TInput, TEmitted>;
365
366
type ObservableActorLogic<TContext, TInput, TEmitted> =
367
ActorLogic<ObservableSnapshot<TContext, TInput>, AnyEventObject, TInput, AnyEventObject, TEmitted>;
368
369
interface ObservableSnapshot<TContext, TInput> extends Snapshot<undefined> {
370
context: TContext;
371
input: TInput;
372
}
373
374
type ObservableActorRef<TContext> = ActorRef<ObservableSnapshot<TContext, any>, AnyEventObject>;
375
```
376
377
### Transition Actors
378
379
Creates actors from transition functions for reducer-like state management.
380
381
```typescript { .api }
382
/**
383
* Creates transition actor logic from a transition function and initial state
384
* @param transition - Function that computes next state given current state and event
385
* @param initialContext - Initial state value or factory function
386
* @returns TransitionActorLogic for reducer-like state management
387
*/
388
function fromTransition<TContext, TEvent extends EventObject, TInput = any, TEmitted = any>(
389
transition: (
390
state: TContext,
391
event: TEvent,
392
actorScope: ActorScope<TContext, TEvent, TEmitted>
393
) => TContext,
394
initialContext: TContext | ((input: TInput) => TContext)
395
): TransitionActorLogic<TContext, TEvent, TInput, TEmitted>;
396
397
type TransitionActorLogic<TContext, TEvent extends EventObject, TInput, TEmitted> =
398
ActorLogic<TransitionSnapshot<TContext>, TEvent, TInput, AnyEventObject, TEmitted>;
399
400
interface TransitionSnapshot<TContext> extends Snapshot<undefined> {
401
context: TContext;
402
}
403
404
type TransitionActorRef<TContext, TEvent extends EventObject> =
405
ActorRef<TransitionSnapshot<TContext>, TEvent>;
406
```
407
408
### Actor Utilities
409
410
Utility functions and types for working with actors and actor systems.
411
412
```typescript { .api }
413
/**
414
* Creates an empty actor with undefined context
415
* @returns Empty actor reference
416
*/
417
function createEmptyActor(): ActorRef<Snapshot<undefined>, AnyEventObject, AnyEventObject>;
418
419
/**
420
* Converts actor to a promise that resolves when actor reaches final state
421
* @param actor - Actor to convert
422
* @returns Promise that resolves with actor output
423
*/
424
function toPromise<TActor extends AnyActorRef>(
425
actor: TActor
426
): Promise<OutputFrom<TActor>>;
427
428
/**
429
* Waits for actor to reach specific conditions
430
* @param actor - Actor to observe
431
* @param predicate - Condition to wait for
432
* @param options - Optional timeout and other options
433
* @returns Promise that resolves when condition is met
434
*/
435
function waitFor<TActor extends AnyActorRef, T>(
436
actor: TActor,
437
predicate: (snapshot: SnapshotFrom<TActor>) => T | undefined,
438
options?: { timeout?: number }
439
): Promise<T>;
440
```
441
442
## Actor System Types
443
444
```typescript { .api }
445
interface ActorSystem<T extends Record<string, AnyActorLogic>> {
446
/** Get actor by ID */
447
get<K extends keyof T>(id: K): ActorRefFrom<T[K]>;
448
/** Register actor logic */
449
register<TActorLogic extends AnyActorLogic>(
450
id: string,
451
actorLogic: TActorLogic
452
): ActorRefFrom<TActorLogic>;
453
}
454
455
interface ActorScope<TContext, TEvent extends EventObject, TEmitted> {
456
/** Reference to this actor */
457
self: ActorRef<any, TEvent>;
458
/** Function to emit events */
459
emit: (event: TEmitted) => void;
460
/** Actor system reference */
461
system: AnyActorSystem;
462
}
463
464
interface Observer<T> {
465
next?: (value: T) => void;
466
error?: (error: any) => void;
467
complete?: () => void;
468
}
469
470
interface Subscription {
471
unsubscribe(): void;
472
}
473
474
interface Subscribable<T> {
475
subscribe(observer: Observer<T>): Subscription;
476
subscribe(
477
next: (value: T) => void,
478
error?: (error: any) => void,
479
complete?: () => void
480
): Subscription;
481
}
482
```