Schema Unions

Schema unions allow you to create types that can be one of several different schemas, similar to TypeScript union types. They use a discriminator field to determine which specific schema an instance represents at runtime, enabling type-safe polymorphism in your Jazz applications.

Creating schema unions

Schema unions are defined with co.discriminatedUnion() by providing an array of schemas and a discriminator field. The discriminator field must be a z.literal().

const 
const ButtonWidget: co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>
ButtonWidget
= import coco.
map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}>(shape: {
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}): co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>
export map
map
({
type: z.z.ZodLiteral<"button">type: import zz.
literal<"button">(value: "button", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"button"> (+1 overload)
export literal
literal
("button"),
label: z.z.ZodStringlabel: import zz.
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload)
export string
string
(),
}); const
const SliderWidget: co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>
SliderWidget
= import coco.
map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}>(shape: {
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}): co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>
export map
map
({
type: z.z.ZodLiteral<"slider">type: import zz.
literal<"slider">(value: "slider", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"slider"> (+1 overload)
export literal
literal
("slider"),
min: z.z.ZodNumbermin: import zz.
function number(params?: string | z.z.core.$ZodNumberParams): z.z.ZodNumber
export number
number
(),
max: z.z.ZodNumbermax: import zz.
function number(params?: string | z.z.core.$ZodNumberParams): z.z.ZodNumber
export number
number
(),
}); const
const Widget: co.DiscriminatedUnion<[co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>, co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>]>
Widget
= import coco.
discriminatedUnion<[co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>, co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>]>(discriminator: string, schemas: [...]): co.DiscriminatedUnion<...>
export discriminatedUnion
discriminatedUnion
("type", [
const ButtonWidget: co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>
ButtonWidget
,
const SliderWidget: co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>
SliderWidget
]);
const
const Dashboard: co.Map<{
    widgets: co.List<co.DiscriminatedUnion<[co.Map<{
        type: z.z.ZodLiteral<"button">;
        label: z.z.ZodString;
    }, unknown, Account | Group>, co.Map<{
        type: z.z.ZodLiteral<"slider">;
        min: z.z.ZodNumber;
        max: z.z.ZodNumber;
    }, unknown, Account | Group>]>>;
}, unknown, Account | Group>
Dashboard
= import coco.
map<{
    widgets: co.List<co.DiscriminatedUnion<[co.Map<{
        type: z.z.ZodLiteral<"button">;
        label: z.z.ZodString;
    }, unknown, Account | Group>, co.Map<{
        type: z.z.ZodLiteral<"slider">;
        min: z.z.ZodNumber;
        max: z.z.ZodNumber;
    }, unknown, Account | Group>]>>;
}>(shape: {
    ...;
}): co.Map<...>
export map
map
({
widgets: co.List<co.DiscriminatedUnion<[co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>, co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>]>>
widgets
: import coco.
list<co.DiscriminatedUnion<[co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>, co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>]>>(element: co.DiscriminatedUnion<...>): co.List<...>
export list
list
(
const Widget: co.DiscriminatedUnion<[co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>, co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>]>
Widget
),
});

To instantiate a schema union, just use the create method of one of the member schemas:

const 
const dashboard: {
    readonly widgets: CoList<({
        readonly type: "button";
        readonly label: string;
    } & CoMap) | ({
        readonly type: "slider";
        readonly min: number;
        readonly max: number;
    } & CoMap)>;
} & CoMap
dashboard
=
const Dashboard: co.Map<{
    widgets: co.List<co.DiscriminatedUnion<[co.Map<{
        type: z.z.ZodLiteral<"button">;
        label: z.z.ZodString;
    }, unknown, Account | Group>, co.Map<{
        type: z.z.ZodLiteral<"slider">;
        min: z.z.ZodNumber;
        max: z.z.ZodNumber;
    }, unknown, Account | Group>]>>;
}, unknown, Account | Group>
Dashboard
.
CoMapSchema<{ widgets: CoListSchema<CoDiscriminatedUnionSchema<[CoMapSchema<{ type: ZodLiteral<"button">; label: ZodString; }, unknown, Account | Group>, CoMapSchema<{ type: ZodLiteral<"slider">; min: ZodNumber; max: ZodNumber; }, unknown, Account | Group>]>>; }, unknown, Account | Group>.create(init: {
    widgets: CoList<({
        readonly type: "button";
        readonly label: string;
    } & CoMap) | ({
        readonly type: "slider";
        readonly min: number;
        readonly max: number;
    } & CoMap) | null> | readonly (NonNullable<...> | ... 1 more ... | {
        ...;
    })[];
}, options?: {
    owner?: Group;
    unique?: CoValueUniqueness["uniqueness"];
} | Group): {
    ...;
} & CoMap (+1 overload)
create
({
widgets: CoList<({
    readonly type: "button";
    readonly label: string;
} & CoMap) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap) | null> | readonly (NonNullable<...> | ... 1 more ... | {
    ...;
})[]
widgets
: [
const ButtonWidget: co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>
ButtonWidget
.
CoMapSchema<{ type: ZodLiteral<"button">; label: ZodString; }, unknown, Account | Group>.create(init: {
    type: "button";
    label: string;
}, options?: {
    owner?: Group;
    unique?: CoValueUniqueness["uniqueness"];
} | Group): {
    ...;
} & CoMap (+1 overload)
create
({ type: "button"type: "button", label: stringlabel: "Click me" }),
const SliderWidget: co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>
SliderWidget
.
CoMapSchema<{ type: ZodLiteral<"slider">; min: ZodNumber; max: ZodNumber; }, unknown, Account | Group>.create(init: {
    type: "slider";
    min: number;
    max: number;
}, options?: {
    owner?: Group;
    unique?: CoValueUniqueness["uniqueness"];
} | Group): {
    ...;
} & CoMap (+1 overload)
create
({ type: "slider"type: "slider", min: numbermin: 0, max: numbermax: 100 })
] });

You can also use plain JSON objects, and let Jazz infer the concrete type from the discriminator field:

const 
const dashboard: {
    readonly widgets: CoList<({
        readonly type: "button";
        readonly label: string;
    } & CoMap) | ({
        readonly type: "slider";
        readonly min: number;
        readonly max: number;
    } & CoMap)>;
} & CoMap
dashboard
=
const Dashboard: co.Map<{
    widgets: co.List<co.DiscriminatedUnion<[co.Map<{
        type: z.z.ZodLiteral<"button">;
        label: z.z.ZodString;
    }, unknown, Account | Group>, co.Map<{
        type: z.z.ZodLiteral<"slider">;
        min: z.z.ZodNumber;
        max: z.z.ZodNumber;
    }, unknown, Account | Group>]>>;
}, unknown, Account | Group>
Dashboard
.
CoMapSchema<{ widgets: CoListSchema<CoDiscriminatedUnionSchema<[CoMapSchema<{ type: ZodLiteral<"button">; label: ZodString; }, unknown, Account | Group>, CoMapSchema<{ type: ZodLiteral<"slider">; min: ZodNumber; max: ZodNumber; }, unknown, Account | Group>]>>; }, unknown, Account | Group>.create(init: {
    widgets: CoList<({
        readonly type: "button";
        readonly label: string;
    } & CoMap) | ({
        readonly type: "slider";
        readonly min: number;
        readonly max: number;
    } & CoMap) | null> | readonly (NonNullable<...> | ... 1 more ... | {
        ...;
    })[];
}, options?: {
    owner?: Group;
    unique?: CoValueUniqueness["uniqueness"];
} | Group): {
    ...;
} & CoMap (+1 overload)
create
({
widgets: CoList<({
    readonly type: "button";
    readonly label: string;
} & CoMap) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap) | null> | readonly (NonNullable<...> | ... 1 more ... | {
    ...;
})[]
widgets
: [
{ type: "button"type: "button", label: stringlabel: "Click me" }, { type: "slider"type: "slider", min: numbermin: 0, max: numbermax: 100 } ] });

Narrowing unions

When working with schema unions, you can access any property that is common to all members of the union. To access properties specific to a particular union member, you need to narrow the type. You can do this using a TypeScript type guard on the discriminator field:

const dashboard: {
    readonly widgets: CoList<({
        readonly type: "button";
        readonly label: string;
    } & CoMap) | ({
        readonly type: "slider";
        readonly min: number;
        readonly max: number;
    } & CoMap)>;
} & CoMap
dashboard
.
widgets: CoList<({
    readonly type: "button";
    readonly label: string;
} & CoMap) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap)>
widgets
.
Array<({ readonly type: "button"; readonly label: string; } & CoMap) | ({ readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap)>.forEach(callbackfn: (value: ({
    readonly type: "button";
    readonly label: string;
} & CoMap) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap), index: number, array: (({
    readonly type: "button";
    readonly label: string;
} & CoMap) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap))[]) => void, thisArg?: any): void
Performs the specified action for each element in an array.
@paramcallbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
forEach
((
widget: ({
    readonly type: "button";
    readonly label: string;
} & CoMap) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap)
widget
) => {
if (
widget: ({
    readonly type: "button";
    readonly label: string;
} & CoMap) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap)
widget
.type: "button" | "slider"type === "button") {
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v20.11.1/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Button: ${
widget: {
    readonly type: "button";
    readonly label: string;
} & CoMap
widget
.label: stringlabel}`);
} else if (
widget: {
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap
widget
.type: "slider"type === "slider") {
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v20.11.1/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Slider: ${
widget: {
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap
widget
.min: numbermin} to ${
widget: {
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap
widget
.max: numbermax}`);
} });

Loading schema unions

You can load an instance of a schema union using its ID, without having to know its concrete type:

// Load a widget by ID
const 
const widget: ({
    readonly type: "button";
    readonly label: string;
} & CoMap & SchemaUnion) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap & SchemaUnion) | null
widget
= await
const Widget: co.DiscriminatedUnion<[co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>, co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>]>
Widget
.
CoDiscriminatedUnionSchema<[CoMapSchema<{ type: ZodLiteral<"button">; label: ZodString; }, unknown, Account | Group>, CoMapSchema<{ type: ZodLiteral<"slider">; min: ZodNumber; max: ZodNumber; }, unknown, Account | Group>]>.load(id: string, options?: {
    loadAs?: Account | AnonymousJazzAgent;
    skipRetry?: boolean;
}): Promise<...>
load
(const widgetId: "widgetId"widgetId);
// Subscribe to updates const const unsubscribe: () => voidunsubscribe =
const Widget: co.DiscriminatedUnion<[co.Map<{
    type: z.z.ZodLiteral<"button">;
    label: z.z.ZodString;
}, unknown, Account | Group>, co.Map<{
    type: z.z.ZodLiteral<"slider">;
    min: z.z.ZodNumber;
    max: z.z.ZodNumber;
}, unknown, Account | Group>]>
Widget
.
CoDiscriminatedUnionSchema<[CoMapSchema<{ type: ZodLiteral<"button">; label: ZodString; }, unknown, Account | Group>, CoMapSchema<{ type: ZodLiteral<"slider">; min: ZodNumber; max: ZodNumber; }, unknown, Account | Group>]>.subscribe(id: string, options: SubscribeListenerOptions<({
    readonly type: "button";
    readonly label: string;
} & CoMap & SchemaUnion) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap & SchemaUnion), true>, listener: (value: ({
    readonly type: "button";
    readonly label: string;
} & ... 1 more ... & SchemaUnion) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & ... 1 more ... & SchemaUnion), unsubscribe: () => void) => void): () => void
subscribe
(const widgetId: "widgetId"widgetId, {}, (
widget: ({
    readonly type: "button";
    readonly label: string;
} & CoMap & SchemaUnion) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap & SchemaUnion)
widget
) => {
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v20.11.1/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("Widget updated:",
widget: ({
    readonly type: "button";
    readonly label: string;
} & CoMap & SchemaUnion) | ({
    readonly type: "slider";
    readonly min: number;
    readonly max: number;
} & CoMap & SchemaUnion)
widget
);
});

Resolve queries are not supported in schema unions yet. If you need to deeply load a schema union, you'll need to first shallowly load the union, and then load the nested properties after narrowing the union type (using $jazz.ensureLoaded or useCoState).

Nested schema unions

You can create complex hierarchies by nesting discriminated unions within other unions:

// Define error types  
const 
const BadRequestError: co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<400>;
    message: z.z.ZodString;
}, unknown, Account | Group>
BadRequestError
= import coco.
map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<400>;
    message: z.z.ZodString;
}>(shape: {
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<400>;
    message: z.z.ZodString;
}): co.Map<...>
export map
map
({
status: z.z.ZodLiteral<"failed">status: import zz.
literal<"failed">(value: "failed", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"failed"> (+1 overload)
export literal
literal
("failed"),
code: z.z.ZodLiteral<400>code: import zz.
literal<400>(value: 400, params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<400> (+1 overload)
export literal
literal
(400),
message: z.z.ZodStringmessage: import zz.
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload)
export string
string
(),
}); const
const UnauthorizedError: co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<401>;
    message: z.z.ZodString;
}, unknown, Account | Group>
UnauthorizedError
= import coco.
map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<401>;
    message: z.z.ZodString;
}>(shape: {
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<401>;
    message: z.z.ZodString;
}): co.Map<...>
export map
map
({
status: z.z.ZodLiteral<"failed">status: import zz.
literal<"failed">(value: "failed", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"failed"> (+1 overload)
export literal
literal
("failed"),
code: z.z.ZodLiteral<401>code: import zz.
literal<401>(value: 401, params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<401> (+1 overload)
export literal
literal
(401),
message: z.z.ZodStringmessage: import zz.
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload)
export string
string
(),
}); const
const InternalServerError: co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<500>;
    message: z.z.ZodString;
}, unknown, Account | Group>
InternalServerError
= import coco.
map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<500>;
    message: z.z.ZodString;
}>(shape: {
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<500>;
    message: z.z.ZodString;
}): co.Map<...>
export map
map
({
status: z.z.ZodLiteral<"failed">status: import zz.
literal<"failed">(value: "failed", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"failed"> (+1 overload)
export literal
literal
("failed"),
code: z.z.ZodLiteral<500>code: import zz.
literal<500>(value: 500, params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<500> (+1 overload)
export literal
literal
(500),
message: z.z.ZodStringmessage: import zz.
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload)
export string
string
(),
}); // Create a union of error types const
const ErrorResponse: co.DiscriminatedUnion<[co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<400>;
    message: z.z.ZodString;
}, unknown, Account | Group>, co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<401>;
    message: z.z.ZodString;
}, unknown, Account | Group>, co.Map<...>]>
ErrorResponse
= import coco.
discriminatedUnion<[co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<400>;
    message: z.z.ZodString;
}, unknown, Account | Group>, co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<...>;
    message: z.z.ZodString;
}, unknown, Account | Group>, co.Map<...>]>(discriminator: string, schemas: [...]): co.DiscriminatedUnion<...>
export discriminatedUnion
discriminatedUnion
("code", [
const BadRequestError: co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<400>;
    message: z.z.ZodString;
}, unknown, Account | Group>
BadRequestError
,
const UnauthorizedError: co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<401>;
    message: z.z.ZodString;
}, unknown, Account | Group>
UnauthorizedError
,
const InternalServerError: co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<500>;
    message: z.z.ZodString;
}, unknown, Account | Group>
InternalServerError
,
]); // Define success type const
const SuccessResponse: co.Map<{
    status: z.z.ZodLiteral<"success">;
    data: z.z.ZodString;
}, unknown, Account | Group>
SuccessResponse
= import coco.
map<{
    status: z.z.ZodLiteral<"success">;
    data: z.z.ZodString;
}>(shape: {
    status: z.z.ZodLiteral<"success">;
    data: z.z.ZodString;
}): co.Map<{
    status: z.z.ZodLiteral<"success">;
    data: z.z.ZodString;
}, unknown, Account | Group>
export map
map
({
status: z.z.ZodLiteral<"success">status: import zz.
literal<"success">(value: "success", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"success"> (+1 overload)
export literal
literal
("success"),
data: z.z.ZodStringdata: import zz.
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload)
export string
string
(),
}); // Create a top-level union that includes the error union const
const ApiResponse: co.DiscriminatedUnion<[co.Map<{
    status: z.z.ZodLiteral<"success">;
    data: z.z.ZodString;
}, unknown, Account | Group>, co.DiscriminatedUnion<[co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<400>;
    message: z.z.ZodString;
}, unknown, Account | Group>, co.Map<...>, co.Map<...>]>]>
ApiResponse
= import coco.
discriminatedUnion<[co.Map<{
    status: z.z.ZodLiteral<"success">;
    data: z.z.ZodString;
}, unknown, Account | Group>, co.DiscriminatedUnion<[co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<400>;
    message: z.z.ZodString;
}, unknown, Account | Group>, co.Map<...>, co.Map<...>]>]>(discriminator: string, schemas: [...]): co.DiscriminatedUnion<...>
export discriminatedUnion
discriminatedUnion
("status", [
const SuccessResponse: co.Map<{
    status: z.z.ZodLiteral<"success">;
    data: z.z.ZodString;
}, unknown, Account | Group>
SuccessResponse
,
const ErrorResponse: co.DiscriminatedUnion<[co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<400>;
    message: z.z.ZodString;
}, unknown, Account | Group>, co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<401>;
    message: z.z.ZodString;
}, unknown, Account | Group>, co.Map<...>]>
ErrorResponse
,
]); function function handleResponse(response: co.loaded<typeof ApiResponse>): voidhandleResponse(
response: NonNullable<({
    readonly status: "failed";
    readonly code: 400;
    readonly message: string;
} & CoMap) | ({
    readonly status: "failed";
    readonly code: 401;
    readonly message: string;
} & CoMap) | ({
    ...;
} & CoMap) | ({
    ...;
} & CoMap) | null>
response
: import coco.
type loaded<T extends CoValueClassOrSchema, R extends ResolveQuery<T> = true> = R extends boolean | undefined ? NonNullable<InstanceOfSchemaCoValuesNullable<T>> : [NonNullable<InstanceOfSchemaCoValuesNullable<T>>] extends [...] ? Exclude<...> extends CoValue ? R extends {
    ...;
} ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends {
    ...;
} ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends {
    ...;
} ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends {
    ...;
} ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends {
    ...;
} ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends {
    ...;
} ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends {
    ...;
} ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends {
    ...;
} ? readonly ((CoValue & ... 1 more ... & (ItemDepth extends boolean ...
export loaded
loaded
<typeof
const ApiResponse: co.DiscriminatedUnion<[co.Map<{
    status: z.z.ZodLiteral<"success">;
    data: z.z.ZodString;
}, unknown, Account | Group>, co.DiscriminatedUnion<[co.Map<{
    status: z.z.ZodLiteral<"failed">;
    code: z.z.ZodLiteral<400>;
    message: z.z.ZodString;
}, unknown, Account | Group>, co.Map<...>, co.Map<...>]>]>
ApiResponse
>) {
if (
response: NonNullable<({
    readonly status: "failed";
    readonly code: 400;
    readonly message: string;
} & CoMap) | ({
    readonly status: "failed";
    readonly code: 401;
    readonly message: string;
} & CoMap) | ({
    ...;
} & CoMap) | ({
    ...;
} & CoMap) | null>
response
.status: "failed" | "success"status === "success") {
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v20.11.1/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("Success:",
response: {
    ...;
} & CoMap
response
.data: stringdata);
} else { // This is an error - narrow further by error code if (
response: ({
    readonly status: "failed";
    readonly code: 400;
    readonly message: string;
} & CoMap) | ({
    readonly status: "failed";
    readonly code: 401;
    readonly message: string;
} & CoMap) | ({
    ...;
} & CoMap)
response
.code: 400 | 401 | 500code === 400) {
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v20.11.1/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("Bad request:",
response: {
    readonly status: "failed";
    readonly code: 400;
    readonly message: string;
} & CoMap
response
.message: stringmessage);
} else if (
response: ({
    readonly status: "failed";
    readonly code: 401;
    readonly message: string;
} & CoMap) | ({
    ...;
} & CoMap)
response
.code: 401 | 500code === 401) {
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v20.11.1/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("Unauthorized:",
response: {
    readonly status: "failed";
    readonly code: 401;
    readonly message: string;
} & CoMap
response
.message: stringmessage);
} else if (
response: {
    ...;
} & CoMap
response
.code: 500code === 500) {
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v20.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v20.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v20.11.1/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+2 overloads)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("Server error:",
response: {
    ...;
} & CoMap
response
.message: stringmessage);
} } }

Limitations with schema unions

Schema unions have some limitations that you should be aware of. They are due to Typescript behavior with type unions: when the type members of the union have methods with generic parameters, Typescript will not allow calling those methods on the union type. This affect some of the methods on the $jazz namespace.

$jazz.ensureLoaded and $jazz.subscribe not supported

The $jazz.ensureLoaded and $jazz.subscribe methods are not available in schema unions. Instead, use the union schema's load and subscribe methods.

Updating union fields

You can't use $jazz.set to modify a schema union's fields (even if the field is present in all the union members). Use $jazz.applyDiff instead.