Defining schemas: CoValues
CoValues ("Collaborative Values") are the core abstraction of Jazz. They're your bread-and-butter datastructures that you use to represent everything in your app.
As their name suggests, CoValues are inherently collaborative, meaning multiple users and devices can edit them at the same time.
Think of CoValues as "super-fast Git for lots of tiny data."
- CoValues keep their full edit histories, from which they derive their "current state".
- The fact that this happens in an eventually-consistent way makes them CRDTs.
- Having the full history also means that you often don't need explicit timestamps and author info - you get this for free as part of a CoValue's edit metadata.
CoValues model JSON with CoMaps and CoLists, but also offer CoFeeds for simple per-user value feeds, and let you represent binary data with FileStreams.
Start your app with a schema
Fundamentally, CoValues are as dynamic and flexible as JSON, but in Jazz you use them by defining fixed schemas to describe the shape of data in your app.
This helps correctness and development speed, but is particularly important...
- when you evolve your app and need migrations
- when different clients and server workers collaborate on CoValues and need to make compatible changes
Thinking about the shape of your data is also a great first step to model your app.
Even before you know the details of how your app will work, you'll probably know which kinds of objects it will deal with, and how they relate to each other.
In Jazz, you define schemas using co
for CoValues and z
(from Zod) for their primitive fields.
// schema.ts import {
import co
co,import z
z } from "jazz-tools"; constconst ListOfTasks: CoListSchema<z.z.ZodString>
ListOfTasks =import co
co.list(
list<z.z.ZodString>(element: z.z.ZodString): CoListSchema<z.z.ZodString> export list
import z
z.string()); export const
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
TodoProject =
const TodoProject: CoMapSchema<{ title: z.z.ZodString; tasks: CoListSchema<z.z.ZodString>; }>
import co
co.map({
map<{ title: z.z.ZodString; tasks: CoListSchema<z.z.ZodString>; }>(shape: { title: z.z.ZodString; tasks: CoListSchema<z.z.ZodString>; }): CoMapSchema<{ title: z.z.ZodString; tasks: CoListSchema<z.z.ZodString>; }> export map
title: z.z.ZodString
title:import z
z.string(),
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
tasks: CoListSchema<z.z.ZodString>
tasks:const ListOfTasks: CoListSchema<z.z.ZodString>
ListOfTasks, });
This gives us schema info that is available for type inference and at runtime.
Check out the inferred type of project
in the example below, as well as the input .create()
expects.
// app.ts import {
class Group
Group } from "jazz-tools"; import {TodoProject,
const TodoProject: CoMapSchema<{ title: ZodString; tasks: CoListSchema<ZodString>; }>
const ListOfTasks: CoListSchema<ZodString>
ListOfTasks } from "./schema"; constproject =
const project: { title: string; tasks: CoList<string>; } & CoMap
TodoProject.
const TodoProject: CoMapSchema<{ title: ZodString; tasks: CoListSchema<ZodString>; }>
create( {
create: (init: { title: string; tasks: CoList<string>; }, options?: Group | Account | { owner: Group | Account; unique?: CoValueUniqueness["uniqueness"]; } | undefined) => { ...; } & CoMap
title: string
title: "New Project",tasks: CoList<string>
tasks:const ListOfTasks: CoListSchema<ZodString>
ListOfTasks.create([],
create: (items: CoListInit<ZodString>, options?: { owner: Account | Group; } | Account | Group) => CoList<string>
class Group
Group.create()), },
Group.create<Group>(this: CoValueClass<Group>, options?: { owner: Account; } | Account): Group
class Group
Group.create() );
Group.create<Group>(this: CoValueClass<Group>, options?: { owner: Account; } | Account): Group
Types of CoValues
CoMap
(declaration)
CoMaps are the most commonly used type of CoValue. They are the equivalent of JSON objects (Collaborative editing follows a last-write-wins strategy per-key).
You can either declare struct-like CoMaps:
const
Task =
const Task: CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>
import co
co.map({
map<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>(shape: { title: z.z.ZodString; completed: z.z.ZodBoolean; }): CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }> export map
title: z.z.ZodString
title:import z
z.string(),
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
completed: z.z.ZodBoolean
completed:import z
z.boolean(), });
function boolean(params?: string | z.z.core.$ZodBooleanParams): z.z.ZodBoolean export boolean
Or record-like CoMaps (key-value pairs, where keys are always string
):
const
const ColorToHex: CoRecordSchema<z.z.ZodString, z.z.ZodString>
ColorToHex =import co
co.record(
record<z.z.ZodString, z.z.ZodString>(_keyType: z.z.ZodString, valueType: z.z.ZodString): CoRecordSchema<z.z.ZodString, z.z.ZodString> export record
import z
z.string(),
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
import z
z.string()); const
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
ColorToFruit =
const ColorToFruit: CoRecordSchema<z.z.ZodString, CoMapSchema<{ name: z.z.ZodString; color: z.z.ZodString; }>>
import co
co.record(
record<z.z.ZodString, CoMapSchema<{ name: z.z.ZodString; color: z.z.ZodString; }>>(_keyType: z.z.ZodString, valueType: CoMapSchema<{ name: z.z.ZodString; color: z.z.ZodString; }>): CoRecordSchema<...> export record
import z
z.string(),
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
Fruit);
const Fruit: CoMapSchema<{ name: z.z.ZodString; color: z.z.ZodString; }>
See the corresponding sections for creating, subscribing/loading, reading from and updating CoMaps.
CoList
(declaration)
CoLists are ordered lists and are the equivalent of JSON arrays. (They support concurrent insertions and deletions, maintaining a consistent order.)
You define them by specifying the type of the items they contain:
const
const ListOfColors: CoListSchema<z.z.ZodString>
ListOfColors =import co
co.list(
list<z.z.ZodString>(element: z.z.ZodString): CoListSchema<z.z.ZodString> export list
import z
z.string()); const
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
ListOfTasks =
const ListOfTasks: CoListSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>
import co
co.list(
list<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>(element: CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>): CoListSchema<...> export list
Task);
const Task: CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>
See the corresponding sections for creating, subscribing/loading, reading from and updating CoLists.
CoFeed
(declaration)
CoFeeds are a special CoValue type that represent a feed of values for a set of users/sessions (Each session of a user gets its own append-only feed).
They allow easy access of the latest or all items belonging to a user or their sessions. This makes them particularly useful for user presence, reactions, notifications, etc.
You define them by specifying the type of feed item:
const
FeedOfTasks =
const FeedOfTasks: CoFeedSchema<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>
import co
co.feed(
feed<CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>>(element: CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>): CoFeedSchema<...> export feed
Task);
const Task: CoMapSchema<{ title: z.z.ZodString; completed: z.z.ZodBoolean; }>
See the corresponding sections for creating, subscribing/loading, reading from and writing to CoFeeds.
FileStream
(declaration)
FileStreams are a special type of CoValue that represent binary data. (They are created by a single user and offer no internal collaboration.)
They allow you to upload and reference files.
You typically don't need to declare or extend them yourself, you simply refer to the built-in co.fileStream()
from another CoValue:
const
Document =
const Document: CoMapSchema<{ title: z.z.ZodString; file: FileStreamSchema; }>
import co
co.map({
map<{ title: z.z.ZodString; file: FileStreamSchema; }>(shape: { title: z.z.ZodString; file: FileStreamSchema; }): CoMapSchema<{ title: z.z.ZodString; file: FileStreamSchema; }> export map
title: z.z.ZodString
title:import z
z.string(),
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
file: FileStreamSchema
file:import co
co.fileStream(), });
function fileStream(): FileStreamSchema export fileStream
See the corresponding sections for creating, subscribing/loading, reading from and writing to FileStreams.
Note: For images, we have a special, higher-level co.image()
helper, see ImageDefinition.
Unions of CoMaps (declaration)
You can declare unions of CoMaps that have discriminating fields, using z.discriminatedUnion()
.
import { co, z } from "jazz-tools"; // ---cut--- const ButtonWidget = co.map({ type: z.literal("button"), label: z.string(), }); const SliderWidget = co.map({ type: z.literal("slider"), min: z.number(), max: z.number(), }); const WidgetUnion = z.discriminatedUnion([ButtonWidget, SliderWidget]);
See the corresponding sections for creating, subscribing/loading and narrowing SchemaUnions.
CoValue field/item types
Now that we've seen the different types of CoValues, let's see more precisely how we declare the fields or items they contain.
Primitive fields
You can declare primitive field types using z
(re-exported in jazz-tools
from Zod):
import {
import co
co,import z
z } from "jazz-tools"; constPerson =
const Person: CoMapSchema<{ title: z.z.ZodString; }>
import co
co.map({
map<{ title: z.z.ZodString; }>(shape: { title: z.z.ZodString; }): CoMapSchema<{ title: z.z.ZodString; }> export map
title: z.z.ZodString
title:import z
z.string(), }) export const
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
const ListOfColors: CoListSchema<z.z.ZodString>
ListOfColors =import co
co.list(
list<z.z.ZodString>(element: z.z.ZodString): CoListSchema<z.z.ZodString> export list
import z
z.string());
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
Here's a quick overview of the primitive types you can use:
import { z } from "jazz-tools"; // ---cut--- z.string(); // For simple strings z.number(); // For numbers z.boolean(); // For booleans z.null(); // For null z.date(); // For dates z.literal(["waiting", "ready"]); // For enums
Finally, for more complex JSON data, that you don't want to be collaborative internally (but only ever update as a whole), you can use more complex Zod types.
For example, you can use z.object()
to represent an internally immutable position:
const
Sprite =
const Sprite: CoMapSchema<{ position: z.z.ZodObject<{ x: z.z.ZodNumber; y: z.z.ZodNumber; }, z.z.core.$strip>; }>
import co
co.map({ // assigned as a whole
map<{ position: z.z.ZodObject<{ x: z.z.ZodNumber; y: z.z.ZodNumber; }, z.z.core.$strip>; }>(shape: { position: z.z.ZodObject<{ x: z.z.ZodNumber; y: z.z.ZodNumber; }, z.z.core.$strip>; }): CoMapSchema<...> export map
position:
position: z.z.ZodObject<{ x: z.z.ZodNumber; y: z.z.ZodNumber; }, z.z.core.$strip>
import z
z.object({
object<{ x: z.z.ZodNumber; y: z.z.ZodNumber; }>(shape?: { x: z.z.ZodNumber; y: z.z.ZodNumber; } | undefined, params?: string | { error?: string | z.z.core.$ZodErrorMap<NonNullable<z.z.core.$ZodIssueInvalidType<unknown> | z.z.core.$ZodIssueUnrecognizedKeys>> | undefined; message?: string | undefined | undefined; } | undefined): z.z.ZodObject<...> export object
x: z.z.ZodNumber
x:import z
z.number(),
function number(params?: string | z.z.core.$ZodNumberParams): z.z.ZodNumber export number
y: z.z.ZodNumber
y:import z
z.number() }), });
function number(params?: string | z.z.core.$ZodNumberParams): z.z.ZodNumber export number
Or you could use a z.tuple()
:
const
Sprite =
const Sprite: CoMapSchema<{ position: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; }>
import co
co.map({ // assigned as a whole
map<{ position: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; }>(shape: { position: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; }): CoMapSchema<{ position: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>; }> export map
position: z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null>
position:import z
z.tuple([
tuple<[z.z.ZodNumber, z.z.ZodNumber]>(items: [z.z.ZodNumber, z.z.ZodNumber], params?: string | z.z.core.$ZodTupleParams): z.z.ZodTuple<[z.z.ZodNumber, z.z.ZodNumber], null> (+2 overloads) export tuple
import z
z.number(),
function number(params?: string | z.z.core.$ZodNumberParams): z.z.ZodNumber export number
import z
z.number()]), });
function number(params?: string | z.z.core.$ZodNumberParams): z.z.ZodNumber export number
References to other CoValues
To represent complex structured data with Jazz, you form trees or graphs of CoValues that reference each other.
Internally, this is represented by storing the IDs of the referenced CoValues in the corresponding fields, but Jazz abstracts this away, making it look like nested CoValues you can get or assign/insert.
The important caveat here is that a referenced CoValue might or might not be loaded yet, but we'll see what exactly that means in Subscribing and Deep Loading.
In Schemas, you declare references by just using the schema of the referenced CoValue:
// schema.ts const
Person =
const Person: CoMapSchema<{ name: z.z.ZodString; }>
import co
co.map({
map<{ name: z.z.ZodString; }>(shape: { name: z.z.ZodString; }): CoMapSchema<{ name: z.z.ZodString; }> export map
name: z.z.ZodString
name:import z
z.string(), }); const
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
ListOfPeople =
const ListOfPeople: CoListSchema<CoMapSchema<{ name: z.z.ZodString; }>>
import co
co.list(
list<CoMapSchema<{ name: z.z.ZodString; }>>(element: CoMapSchema<{ name: z.z.ZodString; }>): CoListSchema<CoMapSchema<{ name: z.z.ZodString; }>> export list
Person); const
const Person: CoMapSchema<{ name: z.z.ZodString; }>
Company =
const Company: CoMapSchema<{ members: CoListSchema<CoMapSchema<{ name: z.z.ZodString; }>>; }>
import co
co.map({
map<{ members: CoListSchema<CoMapSchema<{ name: z.z.ZodString; }>>; }>(shape: { members: CoListSchema<CoMapSchema<{ name: z.z.ZodString; }>>; }): CoMapSchema<...> export map
members:
members: CoListSchema<CoMapSchema<{ name: z.z.ZodString; }>>
ListOfPeople, });
const ListOfPeople: CoListSchema<CoMapSchema<{ name: z.z.ZodString; }>>
Optional References
You can make references optional with z.optional()
:
const
Person =
const Person: CoMapSchema<{ pet: z.ZodOptional<CoMapSchema<{ name: z.z.ZodString; }>>; }>
import co
co.map({
map<{ pet: z.ZodOptional<CoMapSchema<{ name: z.z.ZodString; }>>; }>(shape: { pet: z.ZodOptional<CoMapSchema<{ name: z.z.ZodString; }>>; }): CoMapSchema<{ pet: z.ZodOptional<CoMapSchema<{ name: z.z.ZodString; }>>; }> export map
pet:
pet: z.ZodOptional<CoMapSchema<{ name: z.z.ZodString; }>>
import z
z.optional(
optional<CoMapSchema<{ name: z.z.ZodString; }>>(innerType: CoMapSchema<{ name: z.z.ZodString; }>): z.ZodOptional<CoMapSchema<{ name: z.z.ZodString; }>> export optional
Pet), });
const Pet: CoMapSchema<{ name: z.z.ZodString; }>
Recursive References
You can refer to the same schema from within itself using getters:
const
Person =
const Person: CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: CoMapSchema<...>; }>
import co
co.map({
map<{ name: z.z.ZodString; readonly bestFriend: CoMapSchema<...>; }>(shape: { name: z.z.ZodString; readonly bestFriend: CoMapSchema<...>; }): CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: CoMapSchema<...>; }> export map
name: z.z.ZodString
name:import z
z.string(), get
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
bestFriend() { return
bestFriend: CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: CoMapSchema<...>; }>
Person; } });
const Person: CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: CoMapSchema<...>; }>
You can use the same technique for mutually recursive references, but you'll need to help TypeScript along:
import {
import co
co,import z
z,CoListSchema } from "jazz-tools"; const
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>; }
Person =
const Person: CoMapSchema<{ name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }>
import co
co.map({
map<{ name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }>(shape: { name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }): CoMapSchema<{ name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }> export map
name: z.z.ZodString
name:import z
z.string(), get
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
friends():
friends: CoListSchema<CoMapSchema<{ name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }>>
CoListSchema<typeof
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>; }
Person> { return
const Person: CoMapSchema<{ name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }>
ListOfPeople; } }); const
const ListOfPeople: CoListSchema<CoMapSchema<{ name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }>>
ListOfPeople =
const ListOfPeople: CoListSchema<CoMapSchema<{ name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }>>
import co
co.list(
list<CoMapSchema<{ name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }>>(element: CoMapSchema<{ name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }>): CoListSchema<...> export list
Person);
const Person: CoMapSchema<{ name: z.z.ZodString; readonly friends: CoListSchema<typeof Person>; }>
Note: similarly, if you use modifiers like z.optional()
you'll need to help TypeScript along:
const
Person =
const Person: CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: z.ZodOptional<typeof Person>; }>
import co
co.map({
map<{ name: z.z.ZodString; readonly bestFriend: z.ZodOptional<typeof Person>; }>(shape: { name: z.z.ZodString; readonly bestFriend: z.ZodOptional<typeof Person>; }): CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: z.ZodOptional<typeof Person>; }> export map
name: z.z.ZodString
name:import z
z.string(), get
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
bestFriend():
bestFriend: z.ZodOptional<CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: z.ZodOptional<typeof Person>; }>>
import z
z.ZodOptional<typeof
interface ZodOptional<T extends core.$ZodType = core.$ZodType<unknown, unknown>> export ZodOptional
Person> { return
const Person: CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: z.ZodOptional<typeof Person>; }>
import z
z.optional(
optional<CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: z.ZodOptional<typeof Person>; }>>(innerType: CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: z.ZodOptional<typeof Person>; }>): z.ZodOptional<...> export optional
Person); } });
const Person: CoMapSchema<{ name: z.z.ZodString; readonly bestFriend: z.ZodOptional<typeof Person>; }>
Helper methods
You should define helper methods of CoValue schemas separately, in standalone functions.
const
Person =
const Person: CoMapSchema<{ firstName: z.z.ZodString; lastName: z.z.ZodString; dateOfBirth: z.z.ZodDate; }>
import co
co.map({
map<{ firstName: z.z.ZodString; lastName: z.z.ZodString; dateOfBirth: z.z.ZodDate; }>(shape: { firstName: z.z.ZodString; lastName: z.z.ZodString; dateOfBirth: z.z.ZodDate; }): CoMapSchema<...> export map
firstName: z.z.ZodString
firstName:import z
z.string(),
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
lastName: z.z.ZodString
lastName:import z
z.string(),
function string(params?: string | z.z.core.$ZodStringParams): z.z.ZodString export string
dateOfBirth: z.z.ZodDate
dateOfBirth:import z
z.date(), }) type
function date(params?: string | z.z.core.$ZodDateParams): z.z.ZodDate export date
Person =
type Person = { firstName: string; lastName: string; dateOfBirth: Date; } & 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
Person>; export function
const Person: CoMapSchema<{ firstName: z.z.ZodString; lastName: z.z.ZodString; dateOfBirth: z.z.ZodDate; }>
function getPersonFullName(person: Person): string
getPersonFullName(person:
person: { firstName: string; lastName: string; dateOfBirth: Date; } & CoMap
Person) { return `${
type Person = { firstName: string; lastName: string; dateOfBirth: Date; } & CoMap
person.
person: { firstName: string; lastName: string; dateOfBirth: Date; } & CoMap
firstName: string
firstName} ${person.
person: { firstName: string; lastName: string; dateOfBirth: Date; } & CoMap
lastName: string
lastName}`; } export functionfunction getPersonAgeAsOf(person: Person, date: Date): number
getPersonAgeAsOf(person:
person: { firstName: string; lastName: string; dateOfBirth: Date; } & CoMap
Person,
type Person = { firstName: string; lastName: string; dateOfBirth: Date; } & CoMap
date: Date
date: Date) { returnfunction differenceInYears(date1: Date, date2: Date): number
differenceInYears(date: Date
date,person.
person: { firstName: string; lastName: string; dateOfBirth: Date; } & CoMap
dateOfBirth: Date
dateOfBirth); } constperson =
const person: { firstName: string; lastName: string; dateOfBirth: Date; } & CoMap
Person.
const Person: CoMapSchema<{ firstName: z.z.ZodString; lastName: z.z.ZodString; dateOfBirth: z.z.ZodDate; }>
create({
create: (init: { firstName: string; lastName: string; dateOfBirth: Date; }, options?: Account | Group | { owner: Account | Group; unique?: CoValueUniqueness["uniqueness"]; } | undefined) => { ...; } & CoMap
firstName: string
firstName: "John",lastName: string
lastName: "Doe",dateOfBirth: Date
dateOfBirth: newDate("1990-01-01"), }); const
var Date: DateConstructor new (value: number | string | Date) => Date (+4 overloads)
const fullName: string
fullName =function getPersonFullName(person: Person): string
getPersonFullName(person); const
const person: { firstName: string; lastName: string; dateOfBirth: Date; } & CoMap
const age: number
age =function getPersonAgeAsOf(person: Person, date: Date): number
getPersonAgeAsOf(person, new
const person: { firstName: string; lastName: string; dateOfBirth: Date; } & CoMap
Date());
var Date: DateConstructor new () => Date (+4 overloads)