Actor-based state management & orchestration for complex app logic.
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.
Creates and manages actor instances from various types of actor logic including state machines and specialized actor types.
/**
* Creates an actor instance from actor logic
* @param logic - Actor logic (state machine or other actor logic)
* @param options - Optional configuration for the actor
* @returns Actor instance that can be started, stopped, and communicated with
*/
function createActor<TLogic extends AnyActorLogic>(
logic: TLogic,
options?: ActorOptions<TLogic>
): Actor<TLogic>;
/**
* Legacy alias for createActor
* @deprecated Use createActor instead
*/
function interpret<TLogic extends AnyActorLogic>(
logic: TLogic,
options?: ActorOptions<TLogic>
): Actor<TLogic>;
interface ActorOptions<TLogic extends AnyActorLogic> {
/** Unique identifier for the actor */
id?: string;
/** System identifier for the actor */
systemId?: string;
/** Input data for the actor */
input?: InputFrom<TLogic>;
/** Parent actor reference */
parent?: AnyActorRef;
/** Synchronize snapshot with parent */
syncSnapshot?: boolean;
/** Actor system reference */
system?: AnyActorSystem;
/** Logger for the actor */
logger?: (msg: string) => void;
/** Inspection observer */
inspect?: Observer<InspectionEvent>;
/** DevTools adapter */
devTools?: DevToolsAdapter;
}Usage Examples:
import { createMachine, createActor } from "xstate";
// Create actor from state machine
const machine = createMachine({
initial: "idle",
states: {
idle: {
on: { START: "running" }
},
running: {
on: { STOP: "idle" }
}
}
});
const actor = createActor(machine, {
id: "my-actor",
input: { count: 0 }
});
// Start the actor
actor.start();
// Send events
actor.send({ type: "START" });Main actor implementation providing state management, event handling, and lifecycle control.
class Actor<TLogic extends AnyActorLogic> implements ActorRef<SnapshotFrom<TLogic>, EventFromLogic<TLogic>> {
/** Unique actor identifier */
readonly id: string;
/** Actor logic */
readonly logic: TLogic;
/** Actor options */
readonly options: ActorOptions<TLogic>;
/** Actor status */
readonly status: "not-started" | "running" | "stopped" | "error";
/**
* Starts the actor and begins processing
*/
start(): this;
/**
* Stops the actor and cleans up resources
*/
stop(): this;
/**
* Sends an event to the actor
* @param event - Event to send
*/
send(event: EventFromLogic<TLogic>): void;
/**
* Gets the current snapshot
* @returns Current actor snapshot
*/
getSnapshot(): SnapshotFrom<TLogic>;
/**
* Gets persisted snapshot data
* @returns Persisted snapshot
*/
getPersistedSnapshot(): Snapshot<unknown>;
/**
* Subscribes to actor state changes
* @param observer - Observer function or object
* @returns Subscription object
*/
subscribe(observer: Observer<SnapshotFrom<TLogic>>): Subscription;
/**
* Subscribes to actor state changes with next/error/complete callbacks
* @param nextListener - Called on state changes
* @param errorListener - Called on errors
* @param completeListener - Called on completion
* @returns Subscription object
*/
subscribe(
nextListener: (snapshot: SnapshotFrom<TLogic>) => void,
errorListener?: (error: any) => void,
completeListener?: () => void
): Subscription;
}Interface for communicating with actors, providing a stable API for message passing and observation.
interface ActorRef<
TSnapshot extends Snapshot<unknown>,
TEvent extends EventObject
> {
/** Unique actor identifier */
readonly id: string;
/**
* Sends an event to the actor
* @param event - Event to send
*/
send(event: TEvent): void;
/**
* Subscribes to actor state changes
* @param observer - Observer function or object
* @returns Subscription object
*/
subscribe(observer: Observer<TSnapshot>): Subscription;
/**
* Gets the current snapshot
* @returns Current actor snapshot
*/
getSnapshot(): TSnapshot;
/**
* Gets persisted snapshot data
* @returns Persisted snapshot
*/
getPersistedSnapshot(): Snapshot<unknown>;
/** Symbol.observable implementation */
[Symbol.observable](): InteropObservable<TSnapshot>;
}
interface BaseActorRef<TEvent extends EventObject> {
readonly id: string;
send(event: TEvent): void;
}
type AnyActorRef = ActorRef<any, any>;
type AnyActor = Actor<any>;Creates actors from callback functions for subscription-based or free-form logic with bidirectional communication.
/**
* Creates callback actor logic for subscription-based or free-form logic
* @param callback - Function defining the actor's behavior with access to input, system, self, sendBack, receive, emit
* @returns CallbackActorLogic that can be used to create actors
*/
function fromCallback<
TEvent extends EventObject,
TSentEvent extends EventObject = AnyEventObject,
TInput = any,
TEmitted = any
>(
callback: CallbackLogicFunction<TEvent, TSentEvent, TInput, TEmitted>
): CallbackActorLogic<TEvent, TInput, TEmitted>;
type CallbackLogicFunction<
TEvent extends EventObject,
TSentEvent extends EventObject,
TInput,
TEmitted
> = (params: {
/** Input data provided to the actor */
input: TInput;
/** Actor system reference */
system: AnyActorSystem;
/** Reference to this actor */
self: CallbackActorRef<TEvent, TInput>;
/** Function to send events back to parent */
sendBack: (event: TSentEvent) => void;
/** Function to register event handler */
receive: (listener: (event: TEvent) => void) => void;
/** Function to emit events to external handlers */
emit: (event: TEmitted) => void;
}) => (() => void) | void;
type CallbackActorLogic<TEvent extends EventObject, TInput, TEmitted> =
ActorLogic<CallbackSnapshot<TInput>, TEvent, TInput, AnyEventObject, TEmitted>;
interface CallbackSnapshot<TInput> extends Snapshot<undefined> {
input: TInput;
}
type CallbackActorRef<TEvent extends EventObject, TInput> =
ActorRef<CallbackSnapshot<TInput>, TEvent>;Usage Examples:
import { fromCallback, createActor } from "xstate/actors";
// WebSocket callback actor
const websocketLogic = fromCallback(({ input, sendBack, receive, emit }) => {
const ws = new WebSocket(input.url);
ws.onopen = () => emit({ type: "connected" });
ws.onmessage = (event) => sendBack({ type: "MESSAGE", data: event.data });
ws.onerror = (error) => sendBack({ type: "ERROR", error });
receive((event) => {
if (event.type === "SEND") {
ws.send(event.data);
}
});
return () => ws.close();
});
const actor = createActor(websocketLogic, {
input: { url: "ws://localhost:8080" }
});Creates actors from async functions that resolve to a single value.
/**
* Creates promise actor logic from an async process
* @param promiseCreator - Async function that returns a promise
* @returns PromiseActorLogic that resolves/rejects and emits the result
*/
function fromPromise<TOutput, TInput = any, TEmitted = any>(
promiseCreator: (params: {
input: TInput;
system: AnyActorSystem;
self: PromiseActorRef<TOutput>;
signal: AbortSignal;
emit: (event: TEmitted) => void;
}) => PromiseLike<TOutput>
): PromiseActorLogic<TOutput, TInput, TEmitted>;
type PromiseActorLogic<TOutput, TInput, TEmitted> =
ActorLogic<PromiseSnapshot<TOutput, TInput>, AnyEventObject, TInput, AnyEventObject, TEmitted>;
interface PromiseSnapshot<TOutput, TInput> extends Snapshot<TOutput> {
input: TInput;
}
type PromiseActorRef<TOutput> = ActorRef<PromiseSnapshot<TOutput, any>, AnyEventObject>;Usage Examples:
import { fromPromise, createActor } from "xstate/actors";
// Fetch data promise actor
const fetchUserLogic = fromPromise(async ({ input, signal, emit }) => {
emit({ type: "FETCH_START" });
const response = await fetch(`/api/users/${input.userId}`, {
signal
});
if (!response.ok) {
throw new Error(`Failed to fetch user: ${response.status}`);
}
const user = await response.json();
emit({ type: "FETCH_SUCCESS", user });
return user;
});
const actor = createActor(fetchUserLogic, {
input: { userId: "123" }
});Creates actors from observable streams for reactive programming patterns.
/**
* Creates observable actor logic from an observable stream
* @param observableCreator - Function that creates a subscribable stream
* @returns ObservableActorLogic that emits values from the stream
*/
function fromObservable<TContext, TInput = any, TEmitted = any>(
observableCreator: (params: {
input: TInput;
system: AnyActorSystem;
self: ObservableActorRef<TContext>;
emit: (event: TEmitted) => void;
}) => Subscribable<TContext>
): ObservableActorLogic<TContext, TInput, TEmitted>;
/**
* Creates event observable actor logic that sends events to parent
* @param lazyObservable - Function that creates a subscribable event stream
* @returns ObservableActorLogic that forwards events to parent
*/
function fromEventObservable<TEvent extends EventObject, TInput = any, TEmitted = any>(
lazyObservable: (params: {
input: TInput;
system: AnyActorSystem;
self: ObservableActorRef<TEvent>;
emit: (event: TEmitted) => void;
}) => Subscribable<TEvent>
): ObservableActorLogic<TEvent, TInput, TEmitted>;
type ObservableActorLogic<TContext, TInput, TEmitted> =
ActorLogic<ObservableSnapshot<TContext, TInput>, AnyEventObject, TInput, AnyEventObject, TEmitted>;
interface ObservableSnapshot<TContext, TInput> extends Snapshot<undefined> {
context: TContext;
input: TInput;
}
type ObservableActorRef<TContext> = ActorRef<ObservableSnapshot<TContext, any>, AnyEventObject>;Creates actors from transition functions for reducer-like state management.
/**
* Creates transition actor logic from a transition function and initial state
* @param transition - Function that computes next state given current state and event
* @param initialContext - Initial state value or factory function
* @returns TransitionActorLogic for reducer-like state management
*/
function fromTransition<TContext, TEvent extends EventObject, TInput = any, TEmitted = any>(
transition: (
state: TContext,
event: TEvent,
actorScope: ActorScope<TContext, TEvent, TEmitted>
) => TContext,
initialContext: TContext | ((input: TInput) => TContext)
): TransitionActorLogic<TContext, TEvent, TInput, TEmitted>;
type TransitionActorLogic<TContext, TEvent extends EventObject, TInput, TEmitted> =
ActorLogic<TransitionSnapshot<TContext>, TEvent, TInput, AnyEventObject, TEmitted>;
interface TransitionSnapshot<TContext> extends Snapshot<undefined> {
context: TContext;
}
type TransitionActorRef<TContext, TEvent extends EventObject> =
ActorRef<TransitionSnapshot<TContext>, TEvent>;Utility functions and types for working with actors and actor systems.
/**
* Creates an empty actor with undefined context
* @returns Empty actor reference
*/
function createEmptyActor(): ActorRef<Snapshot<undefined>, AnyEventObject, AnyEventObject>;
/**
* Converts actor to a promise that resolves when actor reaches final state
* @param actor - Actor to convert
* @returns Promise that resolves with actor output
*/
function toPromise<TActor extends AnyActorRef>(
actor: TActor
): Promise<OutputFrom<TActor>>;
/**
* Waits for actor to reach specific conditions
* @param actor - Actor to observe
* @param predicate - Condition to wait for
* @param options - Optional timeout and other options
* @returns Promise that resolves when condition is met
*/
function waitFor<TActor extends AnyActorRef, T>(
actor: TActor,
predicate: (snapshot: SnapshotFrom<TActor>) => T | undefined,
options?: { timeout?: number }
): Promise<T>;interface ActorSystem<T extends Record<string, AnyActorLogic>> {
/** Get actor by ID */
get<K extends keyof T>(id: K): ActorRefFrom<T[K]>;
/** Register actor logic */
register<TActorLogic extends AnyActorLogic>(
id: string,
actorLogic: TActorLogic
): ActorRefFrom<TActorLogic>;
}
interface ActorScope<TContext, TEvent extends EventObject, TEmitted> {
/** Reference to this actor */
self: ActorRef<any, TEvent>;
/** Function to emit events */
emit: (event: TEmitted) => void;
/** Actor system reference */
system: AnyActorSystem;
}
interface Observer<T> {
next?: (value: T) => void;
error?: (error: any) => void;
complete?: () => void;
}
interface Subscription {
unsubscribe(): void;
}
interface Subscribable<T> {
subscribe(observer: Observer<T>): Subscription;
subscribe(
next: (value: T) => void,
error?: (error: any) => void,
complete?: () => void
): Subscription;
}Install with Tessl CLI
npx tessl i tessl/npm-xstate