Connecting CoValues with direct linking
CoValues can form relationships with each other by linking directly to other CoValues. This creates a powerful connection where one CoValue can point to the unique identity of another. Instead of embedding all the details of one CoValue directly within another, you use its Jazz-Tools schema as the field type. This allows multiple CoValues to point to the same piece of data effortlessly.
import {
import co
co,import z
z,Loaded,
type Loaded<T extends CoValueClass | AnyCoSchema, R extends ResolveQuery<T> = true> = R extends boolean | undefined ? NonNullable<InstanceOfSchemaCoValuesNullable<T>> : [NonNullable<InstanceOfSchemaCoValuesNullable<T>>] extends [...] ? Exclude<...> extends CoValue ? R extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...
class Group
Group,class Account
Account } from "jazz-tools"; export constLocation =
const Location: CoMapSchema<{ city: z.z.ZodString; country: z.z.ZodString; }>
import co
co.map({
map<{ city: z.z.ZodString; country: z.z.ZodString; }>(shape: { city: z.z.ZodString; country: z.z.ZodString; }): CoMapSchema<{ city: z.z.ZodString; country: z.z.ZodString; }> export map
city: z.z.ZodString
city:import z
z.string(),
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
country: z.z.ZodString
country:import z
z.string(), }); export type
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
Location =
type Location = { city: string; country: string; } & CoMap
import co
co.loaded<typeof
type loaded<T extends CoValueClass | AnyCoSchema, R extends ResolveQuery<T> = true> = R extends boolean | undefined ? NonNullable<InstanceOfSchemaCoValuesNullable<T>> : [NonNullable<InstanceOfSchemaCoValuesNullable<T>>] extends [...] ? Exclude<...> extends CoValue ? R extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<... export loaded
Location>; // co.ref can be used within CoMap fields to point to other CoValues const
const Location: CoMapSchema<{ city: z.z.ZodString; country: z.z.ZodString; }>
Actor =
const Actor: CoMapSchema<{ name: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; imageURL: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; birthplace: CoMapSchema<...>; }>
import co
co.map({
map<{ name: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; imageURL: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; birthplace: CoMapSchema<...>; }>(shape: { name: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; imageURL: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; birthplace: CoMapSchema<...>; }): CoMapSchema<...> export map
name: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString
name:import z
z.string,
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
imageURL: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString
imageURL:import z
z.string,
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
birthplace:
birthplace: CoMapSchema<{ city: z.z.ZodString; country: z.z.ZodString; }>
Location // Links directly to the Location CoMap above. }) export type
const Location: CoMapSchema<{ city: z.z.ZodString; country: z.z.ZodString; }>
Actor =
type Actor = { name: never; imageURL: never; birthplace: ({ city: string; country: string; } & CoMap) | null; } & CoMap
import co
co.loaded<typeof
type loaded<T extends CoValueClass | AnyCoSchema, R extends ResolveQuery<T> = true> = R extends boolean | undefined ? NonNullable<InstanceOfSchemaCoValuesNullable<T>> : [NonNullable<InstanceOfSchemaCoValuesNullable<T>>] extends [...] ? Exclude<...> extends CoValue ? R extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<... export loaded
Actor>; // actual actor data is stored in the separate Actor CoValue const
const Actor: CoMapSchema<{ name: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; imageURL: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; birthplace: CoMapSchema<...>; }>
Movie =
const Movie: CoMapSchema<{ title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }>
import co
co.map({
map<{ title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }>(shape: { title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }): CoMapSchema<...> export map
title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString
title:import z
z.string,
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString
director:import z
z.string,
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
cast:
cast: CoListSchema<CoMapSchema<{ name: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; imageURL: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; birthplace: CoMapSchema<...>; }>>
import co
co.list(
list<CoMapSchema<{ name: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; imageURL: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; birthplace: CoMapSchema<...>; }>>(element: CoMapSchema<...>): CoListSchema<...> export list
Actor), // ordered, mutable }) export type
const Actor: CoMapSchema<{ name: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; imageURL: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; birthplace: CoMapSchema<...>; }>
Movie =
type Movie = { title: never; director: never; cast: CoList<({ name: never; imageURL: never; birthplace: ({ city: string; country: string; } & CoMap) | null; } & CoMap) | null> | null; } & CoMap
import co
co.loaded<typeof
type loaded<T extends CoValueClass | AnyCoSchema, R extends ResolveQuery<T> = true> = R extends boolean | undefined ? NonNullable<InstanceOfSchemaCoValuesNullable<T>> : [NonNullable<InstanceOfSchemaCoValuesNullable<T>>] extends [...] ? Exclude<...> extends CoValue ? R extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<... export loaded
Movie>; // A User CoMap can maintain a CoFeed of co.ref(Movie) to track their favorite movies const
const Movie: CoMapSchema<{ title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }>
User =
const User: CoMapSchema<{ username: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; favoriteMovies: CoFeedSchema<CoMapSchema<{ title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }>>; }>
import co
co.map({
map<{ username: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; favoriteMovies: CoFeedSchema<CoMapSchema<{ title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }>>; }>(shape: { username: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; favoriteMovies: CoFeedSchema<CoMapSchema<{ title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }>>; }): CoMapSchema<...> export map
username: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString
username:import z
z.string,
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
favoriteMovies:
favoriteMovies: CoFeedSchema<CoMapSchema<{ title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }>>
import co
co.feed(
feed<CoMapSchema<{ title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }>>(element: CoMapSchema<...>): CoFeedSchema<...> export feed
Movie), // append-only }) export type
const Movie: CoMapSchema<{ title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }>
User =
type User = { username: never; favoriteMovies: CoFeed<({ title: never; director: never; cast: CoList<({ name: never; imageURL: never; birthplace: ({ city: string; country: string; } & CoMap) | null; } & CoMap) | null> | null; } & CoMap) | null> | null; } & CoMap
import co
co.loaded<typeof
type loaded<T extends CoValueClass | AnyCoSchema, R extends ResolveQuery<T> = true> = R extends boolean | undefined ? NonNullable<InstanceOfSchemaCoValuesNullable<T>> : [NonNullable<InstanceOfSchemaCoValuesNullable<T>>] extends [...] ? Exclude<...> extends CoValue ? R extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<...> extends CoValue ? ItemDepth extends { ...; } ? ((CoValue & ... 1 more ... & (ItemDepth extends boolean | undefined ? CoValue & Exclude<...> : [...] extends [...] ? Exclude<... export loaded
User>;
const User: CoMapSchema<{ username: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; favoriteMovies: CoFeedSchema<CoMapSchema<{ title: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; director: (params?: string | z.z.core.$ZodStringParams) => z.z.ZodString; cast: CoListSchema<...>; }>>; }>
Understanding CoList and CoFeed
- CoList is a collaborative list where each item is a reference to a CoValue
- CoFeed contains an append-only list of references to CoValues.
This direct linking approach offers a single source of truth. When you update a referenced CoValue, all other CoValues that point to it are automatically updated, ensuring data consistency across your application.
By connecting CoValues through these direct references, you can build robust and collaborative applications where data is consistent, efficient to manage, and relationships are clearly defined. The ability to link different CoValue types to the same underlying data is fundamental to building complex applications with Jazz.
Recursive references with DiscriminatedUnion
In advanced schemas, you may want a CoValue that recursively references itself. For example, a ReferenceItem
that contains a list of other items like NoteItem
or AttachmentItem
. This is common in tree-like structures such as threaded comments or nested project outlines.
You can model this with a Zod z.discriminatedUnion
, but TypeScript’s type inference doesn't handle recursive unions well without a workaround.
Here’s how to structure your schema to avoid circular reference errors.
Use this pattern for recursive discriminated unions
import {
CoListSchema,
type CoListSchema<T extends z.core.$ZodType> = z.z.core.$ZodArray<T> & { collaborative: true; create: (items: CoListInit<T>, options?: { owner: Account | Group; } | Account | Group) => CoList<InstanceOrPrimitiveOfSchema<T>>; load<const R extends RefsToResolve<CoListInstanceCoValuesNullable<T>> = true>(id: string, options?: { resolve?: RefsToResolveStrict<CoListInstanceCoValuesNullable<T>, R>; loadAs?: Account | AnonymousJazzAgent; }): Promise<Resolved<CoListInstanceCoValuesNullable<T>, R> | null>; subscribe<const R extends RefsToResolve<CoListInstanceCoValuesNullable<T>> = true>(id: string, options: SubscribeListenerOptions<CoListInstanceCoValuesNullable<T>, R>, listener: (value: Resolved<CoListInstanceCoValuesNullable<T>, R>, unsubscribe: () => void) => void): () => void; withHelpers<S extends z.z.core.$ZodType, T extends object>(this: S, helpers: (Self: S) => T): WithHelpers<S, T>; getCoSchema: () => typeof CoList; }
import co
co,import z
z } from "jazz-tools"; // Recursive item modeling pattern using discriminated unions // First, define the non-recursive types export constNoteItem =
const NoteItem: CoMapSchema<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>
import co
co.map({
map<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>(shape: { type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }): CoMapSchema<...> export map
type: z.z.ZodLiteral<"note">
type:import z
z.literal("note"),
literal<"note">(value: "note", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"note"> (+1 overload) export literal
internal: z.z.ZodBoolean
internal:import z
z.boolean(),
function boolean(params?: string | z.z.core.$ZodBooleanParams): z.z.ZodBoolean export boolean
content: PlainTextSchema
content:import co
co.plainText(), }); export const
function plainText(): PlainTextSchema export plainText
AttachmentItem =
const AttachmentItem: CoMapSchema<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>
import co
co.map({
map<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>(shape: { type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }): CoMapSchema<...> export map
type: z.z.ZodLiteral<"attachment">
type:import z
z.literal("attachment"),
literal<"attachment">(value: "attachment", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"attachment"> (+1 overload) export literal
internal: z.z.ZodBoolean
internal:import z
z.boolean(),
function boolean(params?: string | z.z.core.$ZodBooleanParams): z.z.ZodBoolean export boolean
content: FileStreamSchema
content:import co
co.fileStream(), }); export const
function fileStream(): FileStreamSchema export fileStream
ReferenceItem =
const ReferenceItem: CoMapSchema<{ type: z.z.ZodLiteral<"reference">; internal: z.z.ZodBoolean; content: z.z.ZodString; readonly children: CoListSchema<z.ZodDiscriminatedUnion<[typeof NoteItem, typeof AttachmentItem, typeof ReferenceItem]>>; }>
import co
co.map({
map<{ type: z.z.ZodLiteral<"reference">; internal: z.z.ZodBoolean; content: z.z.ZodString; readonly children: CoListSchema<z.ZodDiscriminatedUnion<[typeof NoteItem, typeof AttachmentItem, typeof ReferenceItem]>>; }>(shape: { type: z.z.ZodLiteral<"reference">; internal: z.z.ZodBoolean; content: z.z.ZodString; readonly children: CoListSchema<z.ZodDiscriminatedUnion<[typeof NoteItem, typeof AttachmentItem, typeof ReferenceItem]>>; }): CoMapSchema<...> export map
type: z.z.ZodLiteral<"reference">
type:import z
z.literal("reference"),
literal<"reference">(value: "reference", params?: string | z.z.core.$ZodLiteralParams): z.z.ZodLiteral<"reference"> (+1 overload) export literal
internal: z.z.ZodBoolean
internal:import z
z.boolean(),
function boolean(params?: string | z.z.core.$ZodBooleanParams): z.z.ZodBoolean export boolean
content: z.z.ZodString
content:import z
z.string(), // Workaround: declare the field type using CoListSchema and ZodDiscriminatedUnion so TS can safely recurse get
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
children():
children: CoListSchema<z.ZodDiscriminatedUnion<[CoMapSchema<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>, CoMapSchema<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>, CoMapSchema<...>]>>
CoListSchema<
type CoListSchema<T extends z.core.$ZodType> = z.z.core.$ZodArray<T> & { collaborative: true; create: (items: CoListInit<T>, options?: { owner: Account | Group; } | Account | Group) => CoList<InstanceOrPrimitiveOfSchema<T>>; load<const R extends RefsToResolve<CoListInstanceCoValuesNullable<T>> = true>(id: string, options?: { resolve?: RefsToResolveStrict<CoListInstanceCoValuesNullable<T>, R>; loadAs?: Account | AnonymousJazzAgent; }): Promise<Resolved<CoListInstanceCoValuesNullable<T>, R> | null>; subscribe<const R extends RefsToResolve<CoListInstanceCoValuesNullable<T>> = true>(id: string, options: SubscribeListenerOptions<CoListInstanceCoValuesNullable<T>, R>, listener: (value: Resolved<CoListInstanceCoValuesNullable<T>, R>, unsubscribe: () => void) => void): () => void; withHelpers<S extends z.z.core.$ZodType, T extends object>(this: S, helpers: (Self: S) => T): WithHelpers<S, T>; getCoSchema: () => typeof CoList; }
import z
z.ZodDiscriminatedUnion<[typeof
interface ZodDiscriminatedUnion<Options extends readonly core.$ZodType[] = readonly core.$ZodType<unknown, unknown>[]> export ZodDiscriminatedUnion
NoteItem, typeof
const NoteItem: CoMapSchema<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>
AttachmentItem, typeof
const AttachmentItem: CoMapSchema<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>
ReferenceItem]>> { return
const ReferenceItem: CoMapSchema<{ type: z.z.ZodLiteral<"reference">; internal: z.z.ZodBoolean; content: z.z.ZodString; readonly children: CoListSchema<z.ZodDiscriminatedUnion<[typeof NoteItem, typeof AttachmentItem, typeof ReferenceItem]>>; }>
ProjectContextItemList; }, }); // Create the recursive union export const
const ProjectContextItemList: CoListSchema<z.ZodDiscriminatedUnion<[CoMapSchema<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>, CoMapSchema<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>, CoMapSchema<...>]>>
ProjectContextItem =
const ProjectContextItem: z.ZodDiscriminatedUnion<[CoMapSchema<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>, CoMapSchema<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>, CoMapSchema<...>]>
import z
z.discriminatedUnion("type", [
discriminatedUnion<[CoMapSchema<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>, CoMapSchema<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>, CoMapSchema<...>]>(discriminator: string, options: [...], params?: string | z.z.core.$ZodDiscriminatedUnionParams): z.ZodDiscriminatedUnion<...> export discriminatedUnion
NoteItem,
const NoteItem: CoMapSchema<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>
AttachmentItem,
const AttachmentItem: CoMapSchema<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>
ReferenceItem]); // Final list of recursive types export const
const ReferenceItem: CoMapSchema<{ type: z.z.ZodLiteral<"reference">; internal: z.z.ZodBoolean; content: z.z.ZodString; readonly children: CoListSchema<z.ZodDiscriminatedUnion<[typeof NoteItem, typeof AttachmentItem, typeof ReferenceItem]>>; }>
ProjectContextItemList =
const ProjectContextItemList: CoListSchema<z.ZodDiscriminatedUnion<[CoMapSchema<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>, CoMapSchema<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>, CoMapSchema<...>]>>
import co
co.list(
list<z.ZodDiscriminatedUnion<[CoMapSchema<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>, CoMapSchema<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>, CoMapSchema<...>]>>(element: z.ZodDiscriminatedUnion<...>): CoListSchema<...> export list
ProjectContextItem);
const ProjectContextItem: z.ZodDiscriminatedUnion<[CoMapSchema<{ type: z.z.ZodLiteral<"note">; internal: z.z.ZodBoolean; content: PlainTextSchema; }>, CoMapSchema<{ type: z.z.ZodLiteral<"attachment">; internal: z.z.ZodBoolean; content: FileStreamSchema; }>, CoMapSchema<...>]>
Even though this seems like a shortcut, TypeScript and Zod can't resolve the circular reference this way. Always define the discriminated union before introducing recursive links.