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
ButtonWidget =
const ButtonWidget: co.Map<{ type: z.z.ZodLiteral<"button">; label: z.z.ZodString; }, unknown, Account | Group>
import co
co.map({
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
type: z.z.ZodLiteral<"button">
type:import z
z.literal("button"),
literal<"button">(value: "button", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"button"> (+1 overload) export literal
label: z.z.ZodString
label:import z
z.string(), }); const
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload) export string
SliderWidget =
const SliderWidget: co.Map<{ type: z.z.ZodLiteral<"slider">; min: z.z.ZodNumber; max: z.z.ZodNumber; }, unknown, Account | Group>
import co
co.map({
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
type: z.z.ZodLiteral<"slider">
type:import z
z.literal("slider"),
literal<"slider">(value: "slider", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"slider"> (+1 overload) export literal
min: z.z.ZodNumber
min:import z
z.number(),
function number(params?: string | z.z.core.$ZodNumberParams): z.z.ZodNumber export number
max: z.z.ZodNumber
max:import z
z.number(), }); const
function number(params?: string | z.z.core.$ZodNumberParams): z.z.ZodNumber export number
Widget =
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>]>
import co
co.discriminatedUnion("type", [
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
ButtonWidget,
const ButtonWidget: co.Map<{ type: z.z.ZodLiteral<"button">; label: z.z.ZodString; }, unknown, Account | Group>
SliderWidget]); const
const SliderWidget: co.Map<{ type: z.z.ZodLiteral<"slider">; min: z.z.ZodNumber; max: z.z.ZodNumber; }, unknown, Account | Group>
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>
import co
co.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>]>>; }>(shape: { ...; }): co.Map<...> export map
widgets:
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>]>>
import co
co.list(
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
Widget), });
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>]>
To instantiate a schema union, just use the create
method of one of the member schemas:
const
dashboard =
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>
create({
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)
widgets: [
widgets: CoList<({ readonly type: "button"; readonly label: string; } & CoMap) | ({ readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap) | null> | readonly (NonNullable<...> | ... 1 more ... | { ...; })[]
ButtonWidget.
const ButtonWidget: co.Map<{ type: z.z.ZodLiteral<"button">; label: z.z.ZodString; }, unknown, Account | Group>
create({
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)
type: "button"
type: "button",label: string
label: "Click me" }),SliderWidget.
const SliderWidget: co.Map<{ type: z.z.ZodLiteral<"slider">; min: z.z.ZodNumber; max: z.z.ZodNumber; }, unknown, Account | Group>
create({
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)
type: "slider"
type: "slider",min: number
min: 0,max: number
max: 100 }) ] });
You can also use plain JSON objects, and let Jazz infer the concrete type from the discriminator field:
const
dashboard =
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>
create({
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)
widgets: [ {
widgets: CoList<({ readonly type: "button"; readonly label: string; } & CoMap) | ({ readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap) | null> | readonly (NonNullable<...> | ... 1 more ... | { ...; })[]
type: "button"
type: "button",label: string
label: "Click me" }, {type: "slider"
type: "slider",min: number
min: 0,max: number
max: 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:
dashboard.
const dashboard: { readonly widgets: CoList<({ readonly type: "button"; readonly label: string; } & CoMap) | ({ readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap)>; } & CoMap
widgets.
widgets: CoList<({ readonly type: "button"; readonly label: string; } & CoMap) | ({ readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap)>
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.forEach((widget) => { if (
widget: ({ readonly type: "button"; readonly label: string; } & CoMap) | ({ readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap)
widget.
widget: ({ readonly type: "button"; readonly label: string; } & CoMap) | ({ readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap)
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 ```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.
widget: { readonly type: "button"; readonly label: string; } & CoMap
label: string
label}`); } else if (widget.
widget: { readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap
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 ```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.
widget: { readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap
min: number
min} to ${widget.
widget: { readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap
max: number
max}`); } });
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
widget = await
const widget: ({ readonly type: "button"; readonly label: string; } & CoMap & SchemaUnion) | ({ readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap & SchemaUnion) | null
Widget.
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>]>
load(
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<...>
const widgetId: "widgetId"
widgetId); // Subscribe to updates constconst unsubscribe: () => void
unsubscribe =Widget.
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>]>
subscribe(
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
const widgetId: "widgetId"
widgetId, {}, (widget) => {
widget: ({ readonly type: "button"; readonly label: string; } & CoMap & SchemaUnion) | ({ readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap & SchemaUnion)
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 ```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); });
widget: ({ readonly type: "button"; readonly label: string; } & CoMap & SchemaUnion) | ({ readonly type: "slider"; readonly min: number; readonly max: number; } & CoMap & SchemaUnion)
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
BadRequestError =
const BadRequestError: co.Map<{ status: z.z.ZodLiteral<"failed">; code: z.z.ZodLiteral<400>; message: z.z.ZodString; }, unknown, Account | Group>
import co
co.map({
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
status: z.z.ZodLiteral<"failed">
status:import z
z.literal("failed"),
literal<"failed">(value: "failed", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"failed"> (+1 overload) export literal
code: z.z.ZodLiteral<400>
code:import z
z.literal(400),
literal<400>(value: 400, params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<400> (+1 overload) export literal
message: z.z.ZodString
message:import z
z.string(), }); const
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload) export string
UnauthorizedError =
const UnauthorizedError: co.Map<{ status: z.z.ZodLiteral<"failed">; code: z.z.ZodLiteral<401>; message: z.z.ZodString; }, unknown, Account | Group>
import co
co.map({
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
status: z.z.ZodLiteral<"failed">
status:import z
z.literal("failed"),
literal<"failed">(value: "failed", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"failed"> (+1 overload) export literal
code: z.z.ZodLiteral<401>
code:import z
z.literal(401),
literal<401>(value: 401, params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<401> (+1 overload) export literal
message: z.z.ZodString
message:import z
z.string(), }); const
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload) export string
InternalServerError =
const InternalServerError: co.Map<{ status: z.z.ZodLiteral<"failed">; code: z.z.ZodLiteral<500>; message: z.z.ZodString; }, unknown, Account | Group>
import co
co.map({
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
status: z.z.ZodLiteral<"failed">
status:import z
z.literal("failed"),
literal<"failed">(value: "failed", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"failed"> (+1 overload) export literal
code: z.z.ZodLiteral<500>
code:import z
z.literal(500),
literal<500>(value: 500, params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<500> (+1 overload) export literal
message: z.z.ZodString
message:import z
z.string(), }); // Create a union of error types const
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload) export string
ErrorResponse =
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<...>]>
import co
co.discriminatedUnion("code", [
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
BadRequestError,
const BadRequestError: co.Map<{ status: z.z.ZodLiteral<"failed">; code: z.z.ZodLiteral<400>; message: z.z.ZodString; }, unknown, Account | Group>
UnauthorizedError,
const UnauthorizedError: co.Map<{ status: z.z.ZodLiteral<"failed">; code: z.z.ZodLiteral<401>; message: z.z.ZodString; }, unknown, Account | Group>
InternalServerError, ]); // Define success type const
const InternalServerError: co.Map<{ status: z.z.ZodLiteral<"failed">; code: z.z.ZodLiteral<500>; message: z.z.ZodString; }, unknown, Account | Group>
SuccessResponse =
const SuccessResponse: co.Map<{ status: z.z.ZodLiteral<"success">; data: z.z.ZodString; }, unknown, Account | Group>
import co
co.map({
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
status: z.z.ZodLiteral<"success">
status:import z
z.literal("success"),
literal<"success">(value: "success", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"success"> (+1 overload) export literal
data: z.z.ZodString
data:import z
z.string(), }); // Create a top-level union that includes the error union const
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString (+1 overload) export string
ApiResponse =
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<...>]>]>
import co
co.discriminatedUnion("status", [
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
SuccessResponse,
const SuccessResponse: co.Map<{ status: z.z.ZodLiteral<"success">; data: z.z.ZodString; }, unknown, Account | Group>
ErrorResponse, ]); function
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<...>]>
function handleResponse(response: co.loaded<typeof ApiResponse>): void
handleResponse(response:
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>
import co
co.loaded<typeof
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
ApiResponse>) { if (
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<...>]>]>
response.
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>
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 ```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.
response: { ...; } & CoMap
data: string
data); } else { // This is an error - narrow further by error code if (response.
response: ({ readonly status: "failed"; readonly code: 400; readonly message: string; } & CoMap) | ({ readonly status: "failed"; readonly code: 401; readonly message: string; } & CoMap) | ({ ...; } & CoMap)
code: 400 | 401 | 500
code === 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 ```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.
response: { readonly status: "failed"; readonly code: 400; readonly message: string; } & CoMap
message: string
message); } else if (response.
response: ({ readonly status: "failed"; readonly code: 401; readonly message: string; } & CoMap) | ({ ...; } & CoMap)
code: 401 | 500
code === 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 ```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.
response: { readonly status: "failed"; readonly code: 401; readonly message: string; } & CoMap
message: string
message); } else if (response.
response: { ...; } & CoMap
code: 500
code === 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 ```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.
response: { ...; } & CoMap
message: string
message); } } }
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.