Spawn typed
A Behavior<T> is a value. To put it into the runtime — to get
an actual ActorRef<T> you can tell messages to — use the
method on whichever host you’re spawning from:
| Where | Method |
|---|---|
| Outside an actor | system.spawnTyped(behavior, name) / system.spawnTypedAnonymous(behavior) |
Inside an untyped Actor.onReceive | this.context.spawnTyped(behavior, name) / this.context.spawnTypedAnonymous(behavior) |
Inside a typed Behaviors.setup / handler | context.spawn(behavior, name) |
| Anywhere an actor class or factory is accepted | typedActor(behavior) |
The method form mirrors the standard OO API — spawn vs.
spawnAnonymous for whether you supply a name.
system.spawnTyped — top-level
Section titled “system.spawnTyped — top-level”import { match } from 'ts-pattern';import { ActorSystem, Behaviors, type Behavior, type ActorRef } from 'actor-ts';
type IncrementCommand = { kind: 'increment' };type GetCommand = { kind: 'get'; replyTo: ActorRef<number> };type Command = IncrementCommand | GetCommand;
const counter = (n: number): Behavior<Command> => Behaviors.receive((context, command) => match(command) .with({ kind: 'increment' }, () => counter(n + 1)) .with({ kind: 'get' }, (c) => { c.replyTo.tell(n); return Behaviors.same; }) .exhaustive());
const system = ActorSystem.create('demo');const ref = system.spawnTyped(counter(0), 'counter');// ^- ActorRef<Command>The signatures:
class ActorSystem { spawnTyped<T>(behavior: Behavior<T>, name: string): ActorRef<T>; spawnTypedAnonymous<T>(behavior: Behavior<T>): ActorRef<T>;}Returns a typed ActorRef<T> — tell accepts only Command-shaped
messages, the compiler enforces it.
ctx.spawnTyped — typed child from an untyped parent
Section titled “ctx.spawnTyped — typed child from an untyped parent”import { Actor, Behaviors } from 'actor-ts';
class UntypedParent extends Actor<...> { override preStart(): void { const typedChild = this.context.spawnTyped(counter(0), 'child'); // typedChild: ActorRef<Command> typedChild.tell({ kind: 'increment' }); }}The signatures live on ActorContext:
interface ActorContext { spawnTyped<T>(behavior: Behavior<T>, name: string): ActorRef<T>; spawnTypedAnonymous<T>(behavior: Behavior<T>): ActorRef<T>;}Useful when you have an existing untyped supervisor that needs to spawn typed workers. The child is a normal entry in the parent’s children list — supervisor strategies apply per the parent’s strategy, death watch works both ways.
typedActor — interop with the class-or-factory API
Section titled “typedActor — interop with the class-or-factory API”import { ActorOptions, typedActor } from 'actor-ts';
const counterActor = typedActor(counter(0));const counterOptions = ActorOptions.create<Command>() .withMailboxCapacity(500) .withDispatcher(myDispatcher);
const ref = system.spawn(counterActor, 'counter', counterOptions);When you want a typed Behavior but the API takes an actor — an
entry point that predates the typed layer, or a spawn that needs
ActorOptions of its own — typedActor(behavior) returns the
ActorFactory<T> those places accept.
The shape:
function typedActor<T>(behavior: Behavior<T>): ActorFactory<T>;The returned factory can be passed anywhere an actor is expected —
system.spawn, context.spawn, ClusterSingleton.start, the
sharding region’s entityActor slot.
Typed-actor-to-typed-child: ctx.spawn
Section titled “Typed-actor-to-typed-child: ctx.spawn”Inside a typed handler, the context exposes its own spawn:
const parent: Behavior<ParentMessage> = Behaviors.setup((context) => { const child = context.spawn(workerBehavior, 'worker'); // ^- ActorRef<WorkerMessage>
return Behaviors.receive((context, message) => { child.tell({ kind: 'do-it' }); return Behaviors.same; });});This is the standard way for typed parents to spawn typed
children — typed all the way through. context.spawn(behavior) knows
the child’s message type from the Behavior’s type parameter.
Naming + paths
Section titled “Naming + paths”For the deterministic variants (spawnTyped), the name parameter
is required and must be unique among siblings. For
spawnTypedAnonymous, the framework generates one — $anonymous-,
a per-parent counter and twelve random hex characters, for example
'$anonymous-1-3f9c1a0d7b42'. The suffix is random, so the path is
not stable across runs; use spawnTyped whenever you need to
address the actor by path.
The resulting actor’s path follows the standard format:
system.spawnTyped(b, 'counter')→actor-ts://my-app/user/counterparentContext.spawnTyped(b, 'worker')→actor-ts://my-app/user/<parent>/workercontext.spawn(b, 'worker')→actor-ts://my-app/user/<parent>/worker
See Actor paths for the path semantics.
When to use which
Section titled “When to use which”Caller is outside an actor: → system.spawnTyped(b, name) // with a name → system.spawnTypedAnonymous(b) // throwaway
Caller is inside an untyped Actor.onReceive: → this.context.spawnTyped(b, name) → this.context.spawnTypedAnonymous(b)
Caller is inside a typed Behaviors.setup or handler: → context.spawn(b, name)
You have a function that takes an actor and you want to use a Behavior: → typedActor(b)The methods are deliberately small — each handles one common
case. typedActor is the escape hatch when you need to plug a
behavior into actor-shaped APIs.
Where to next
Section titled “Where to next”- Behaviors — the DSL that produces the values you pass to these methods.
- Typed actor — the runtime the spawn methods wrap.
- Spawning actors — the untyped
configuration
typedActorreturns. - Actor system — the
spawnAPI the methods ultimately call.
