← Prototype lesson
Lab

Prototype

type Query = { minutes: number; filters: string[] };
type Definition = Readonly<{ name: string; version: number }>;

class IncidentCard {
  id: string;
  query: Query;
  definition: Definition;
  preview: number | null;

  constructor(
    id: string,
    query: Query,
    definition: Definition,
    preview: number | null,
  ) {
    this.id = id;
    this.query = query;
    this.definition = definition;
    this.preview = preview;
  }

  // The prototype: the card decides what its duplicate owns and shares.
  duplicate(newId: string): IncidentCard {
    const query = {
      minutes: this.query.minutes,
      filters: [...this.query.filters],
    };
    return new IncidentCard(newId, query, this.definition, null);
  }

  edit(minutes: number, firstFilter: string): void {
    this.query.minutes = minutes;
    this.query.filters[0] = firstFilter;
    this.preview = null;
  }
}

const definition = Object.freeze({ name: 'Incident feed', version: 1 });
const query = { minutes: 15, filters: ['http-5xx', 'timeout'] };
const source = new IncidentCard('preset-api', query, definition, 42);

// Duplicate the configured card, edit the copy, then copy the copy.
const a = source.duplicate('card-a');
a.edit(30, 'latency');
const b = a.duplicate('card-b');
const sharedDefinition = a.definition === source.definition;

function show(card: IncidentCard) {
  const filters = card.query.filters.join(',');
  const preview = card.preview ?? '-';
  console.log(`${card.id}: ${card.query.minutes}m ${filters} preview=${preview}`);
}
show(source);
show(a);
show(b);
const about = `${definition.name} v${definition.version}`;
console.log(`definition: ${about}, shared=${sharedDefinition}`);

A configured card copies itself. Query data, shared definition and preview have different policies.

Read-only definition · recorded targets
The shared target appears when recorded.
At this recorded stop

Bindings appear as the program creates them.

— means unavailable; none and quiet are recorded values.

Each binding keeps its place. Equal labels do not imply one object. Inspect recorded objects for all fields. Dimmed rows retain earlier observations.

Play or Run to observe the copy boundaries. Unavailable fields remain —.