Skip to content

Types

Zocket’s type system is built around inference — you define actors once and the types flow through to the client and React layers automatically. The @zocket/core package exports several utility types for advanced use cases.

Extract the output type from any Standard Schema:

import type { InferSchema } from "@zocket/core";
import { z } from "zod";
const UserSchema = z.object({ name: z.string(), age: z.number() });
type User = InferSchema<typeof UserSchema>;
// { name: string; age: number }

Extract the state type from an ActorDef:

import type { InferState } from "@zocket/core";
type ChatState = InferState<typeof ChatRoom>;
// { messages: { text: string; from: string }[] }

Map an actor’s method definitions to callable signatures:

import type { InferMethods } from "@zocket/core";
type ChatMethods = InferMethods<typeof ChatRoom>;
// {
// sendMessage: (input: { text: string }) => Promise<void>;
// getHistory: () => Promise<Message[]>;
// }

Methods with an input schema produce (input: T) => Promise<R>. Methods without input produce () => Promise<R>.

Map event definitions to callback signatures:

import type { InferEvents } from "@zocket/core";
type ChatEvents = InferEvents<typeof ChatRoom>;
// {
// newMessage: (payload: { text: string; from: string }) => void;
// }

The client-facing typed handle for an actor instance. This is what client.chat("room-1") returns:

type ActorHandle<T extends ActorDef> = InferMethods<T> & {
on: <K extends keyof InferEvents<T>>(
event: K,
callback: InferEvents<T>[K],
) => Unsubscribe;
state: {
subscribe: (listener: (state: InferState<T>) => void) => Unsubscribe;
getSnapshot: () => InferState<T> | undefined;
};
meta: ActorHandleMeta;
};
interface ActorHandleMeta {
name: string;
id: string;
dispose: () => void;
}

Maps an AppDef to the client’s top-level API shape:

type ClientApi<T extends AppDef> = {
[K in keyof T["actors"]]: (id: string) => ActorHandle<T["actors"][K]>;
};

So for an app with { actors: { chat: ChatRoom, game: GameMatch } }, the client type is:

{
chat: (id: string) => ActorHandle<typeof ChatRoom>;
game: (id: string) => ActorHandle<typeof GameMatch>;
}

Constrains event names and payload types to declared events:

type TypedEmitFn<TEvents> = <K extends keyof TEvents>(
event: K,
payload: InferSchema<TEvents[K]>,
) => void;

Used internally by MethodContext. The emit function in handlers is automatically typed.

Extract the payload type from a specific event:

import type { EventPayload } from "@zocket/core";
type MsgPayload = EventPayload<typeof ChatRoom, "newMessage">;
// { text: string; from: string }

For low-level protocol work, these types are also exported:

import type {
RpcCallMessage,
RpcResultMessage,
EventMessage,
StateSnapshotMessage,
StatePatchMessage,
JsonPatchOp,
ClientMessage,
ServerMessage,
} from "@zocket/core/types";

See the Protocol page for details on each message format.