CoMaps

CoMaps are key-value objects that work like JavaScript objects. You can access properties with dot notation and define typed fields that provide TypeScript safety. They're ideal for structured data that needs type validation.

Creating CoMaps

CoMaps are typically defined by extending the CoMap class and specifying primitive fields using the co declarer (see Defining schemas: CoValues for more details on primitive fields):

class Project extends CoMap { name = co.string; startDate = co.Date; status = co.literal("planning", "active", "completed"); coordinator = co.optional.ref(Member); }

You can create either struct-like CoMaps with fixed fields (as above) or record-like CoMaps for key-value pairs:

class Inventory extends CoMap.Record(co.number) {}

To instantiate a CoMap:

const project = Project.create({ name: "Spring Planting", startDate: new Date("2025-03-15"), status: "planning", }); const inventory = Inventory.create({ tomatoes: 48, basil: 12, });

Ownership

When creating CoMaps, you can specify ownership to control access:

// Create with default owner (current user) const privateProject = Project.create({ name: "My Herb Garden", startDate: new Date("2025-04-01"), status: "planning", }); // Create with shared ownership const gardenGroup = Group.create(); gardenGroup.addMember(memberAccount, "writer"); const communityProject = Project.create( { name: "Community Vegetable Plot", startDate: new Date("2025-03-20"), status: "planning", }, { owner: gardenGroup }, );

Reading from CoMaps

CoMaps can be accessed using familiar JavaScript object notation:

console.log(project.name); // "Spring Planting" console.log(project.status); // "planning"

Handling Optional Fields

Optional fields require checks before access:

if (project.coordinator) { console.log(project.coordinator.name); // Safe access }

Working with Record CoMaps

For record-type CoMaps, you can access values using bracket notation:

const inventory = Inventory.create({ tomatoes: 48, peppers: 24, basil: 12 }); console.log(inventory["tomatoes"]); // 48

Updating CoMaps

Updating CoMap properties uses standard JavaScript assignment:

project.name = "Spring Vegetable Garden"; // Update name project.startDate = new Date("2025-03-20"); // Update date

Type Safety

CoMaps are fully typed in TypeScript, giving you autocomplete and error checking:

project.name = "Spring Vegetable Planting"; // ✓ Valid string project.startDate = "2025-03-15"; // ✗ Type error: expected Date

Deleting Properties

You can delete properties from CoMaps:

delete inventory["basil"]; // Remove a key-value pair // For optional fields in struct-like CoMaps project.coordinator = null; // Remove the reference

Best Practices

Structuring Data

  • Use struct-like CoMaps for entities with fixed, known properties
  • Use record-like CoMaps for dynamic key-value collections
  • Group related properties into nested CoMaps for better organization

Common Patterns

Using Computed Properties

CoMaps support computed properties and methods:

class ComputedProject extends CoMap { name = co.string; startDate = co.Date; endDate = co.optional.Date; get isActive() { const now = new Date(); return now >= this.startDate && (!this.endDate || now <= this.endDate); } formatDuration(format: "short" | "full") { const start = this.startDate.toLocaleDateString(); if (!this.endDate) { return format === "full" ? `Started on ${start}, ongoing` : `From ${start}`; } const end = this.endDate.toLocaleDateString(); return format === "full" ? `From ${start} to ${end}` : `${(this.endDate.getTime() - this.startDate.getTime()) / 86400000} days`; } } // ... console.log(computedProject.isActive); // false console.log(computedProject.formatDuration("short")); // "3 days"