Function: defineComponents()
Documentation / @xmachines/play-catalog / defineComponents
function defineComponents<TCatalog, TComponents>( catalog, components,): NoExtraKeys<TComponents, TCatalog>;Defined in: define-components.ts:116
Define components matching catalog schema with compile-time validation
Enforces bidirectional validation between catalog and component implementations:
- All catalog keys must have corresponding components (no missing components)
- No extra components outside catalog (no undefined keys)
- TypeScript compilation fails for mismatches (build-time safety)
Architectural Context: Implements Strict Separation (INV-02) by validating
that framework components (React/Vue/etc.) exactly match the framework-agnostic
catalog that the Actor references. This ensures the Actor can reference component
names in meta.view without importing framework code.
Type Parameters
| Type Parameter |
|---|
TCatalog extends Record<string, ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>> |
TComponents extends ComponentsFor<TCatalog> |
Parameters
| Parameter | Type | Description |
|---|---|---|
catalog | TCatalog | Component catalog with Zod schemas |
components | NoExtraKeys<TComponents, TCatalog> | Component implementations matching catalog keys exactly |
Returns
NoExtraKeys<TComponents, TCatalog>
Component map validated at compile time (frozen in development)
Throws
Error if runtime validation detects missing or extra keys
Examples
Valid component definition
import { defineComponents } from "@xmachines/play-catalog";import { catalog } from "./catalog.js";import { DashboardComponent, LoginFormComponent } from "./components.js";
// ✅ Valid - all keys match catalogconst components = defineComponents(catalog, { Dashboard: DashboardComponent, LoginForm: LoginFormComponent,});TypeScript compile errors
import { defineComponents } from "@xmachines/play-catalog";import { catalog } from "./catalog.js";
// ❌ TypeScript error - missing 'LoginForm'const components = defineComponents(catalog, { Dashboard: DashboardComponent,});
// ❌ TypeScript error - extra 'UnknownComponent' not in catalogconst components = defineComponents(catalog, { Dashboard: DashboardComponent, LoginForm: LoginFormComponent, UnknownComponent: SomeComponent,});Progressive example with Actor integration
import { z } from "zod";import { defineCatalog, defineComponents } from "@xmachines/play-catalog";import { definePlayer } from "@xmachines/play-xstate";import { setup } from "xstate";
// 1. Define catalogconst catalog = defineCatalog({ HomePage: z.object({}), Dashboard: z.object({ userId: z.string() })});
// 2. Define componentsconst components = defineComponents(catalog, { HomePage: () => <div>Home</div>, Dashboard: ({ userId }) => <div>Dashboard for {userId}</div>});
// 3. Create machine referencing catalog componentsconst machine = setup({}).createMachine({ initial: 'home', states: { home: { meta: { route: '/', view: { component: 'HomePage' } // References catalog key } }, dashboard: { meta: { route: '/dashboard', view: { component: 'Dashboard', userId: '123' } } } }});
// 4. Create actor with catalogconst createPlayer = definePlayer({ machine, catalog });const actor = createPlayer();See
- RFC Play v1 - Invariant INV-02
- defineCatalog for creating the catalog schema
- Catalog for the catalog type definition