Add a renamed event with a validated id and nonblank title in a local copy. The type map should make a new channel required. The exhaustive switch should require a dispatch branch. Neither mechanism automatically writes the decoder: add an unknown-data branch that validates and projects the new payload.
Keep the same contract around callback returns, duplicate subscriptions, snapshot behavior and disposal. A new event should not silently change the lifetime rules of every existing port. Test a valid renamed message, a blank title, extra-field removal and the actual subscriber payload.
Add a positive public consumer and a focused negative caller missing title. Then run the declaration-consumer checks and runtime suite. A clean mapped registry alone cannot prove the new parser accepts the intended wire data.
The exercise below rehearses coverage on a small formatter registry. The full extension remains your independent integration work; compare each affected file before calling it done.
Predict, check, and run
Write the output before running. Use Check types first, then Check & run. Types disappear at runtime: explain both what the compiler checks and what the code actually does. Each editor is an independent ES module; await asynchronous work explicitly.
type Events = {
added: { title: string };
renamed: { title: string };
};
type Labels<E> = { [K in keyof E]: (payload: E[K]) => string };
const labels = {
added: book => `Added ${book.title}`,
renamed: book => `Renamed ${book.title}`
} satisfies Labels<Events>;
console.log(labels.renamed({ title: "Types" }));Enable JavaScript to edit and type-check this example.
Check your prediction
Renamed Types Add a vocabulary branch and its runtime evidence together
Adding renamed to EventMap demands channel coverage and an exhaustive dispatch branch. It does not instantiate a port, decode wire data or choose normalization rules. Write one accepted raw record and several rejected records before editing the type map.
Reuse checked id construction and preserve the existing lifetime policy. A new event must not accidentally permit asynchronous listeners or change how disposal and callback failure behave for every old event.
| Boundary or case | What to inspect |
|---|---|
| Map and channels | Require exactly the renamed payload contract |
| Decoder and dispatch | Validate the raw branch and route a correlated payload |
| Consumer and runtime | Reject missing title and verify actual normalized subscriber data |
Follow coverage errors, then add invalid runtime fixtures the checker cannot inspect. Re-run existing snapshot, cleanup and failure tests after the new happy path works. Explain which file owns each guarantee instead of copying the branch blindly.
Build it yourself
Extending Event Contracts: practise
Create a formatter registry covering added, removed and renamed payloads. Added and renamed use title; removed uses id. Print Renamed Types and Removed b1. Use satisfies to require every key.
// Start from the stated contract. Add a valid call and an edge case.Enable JavaScript to edit and type-check this example.
Hint 1: the idea
The new key should be required by the mapped contract, not manually asserted as present.
Hint 2: a first step
Add renamed to the event map before constructing the complete registry.
Show one solution
type Events = {
added: { title: string };
removed: { id: string };
renamed: { title: string };
};
type Labels<E> = { [K in keyof E]: (payload: E[K]) => string };
const labels = {
added: book => `Added ${book.title}`,
removed: book => `Removed ${book.id}`,
renamed: book => `Renamed ${book.title}`
} satisfies Labels<Events>;
console.log(labels.renamed({ title: "Types" }));
console.log(labels.removed({ id: "b1" }));Enable JavaScript to edit and type-check this example.
Renamed Types
Removed b1Trace the implementation against the task before comparing styles. A passing example supports that case; use the changes below to challenge the wider contract.
Change it and test it
In the local project, list the expected compiler failures immediately after adding the map key. Then add decoder behavior and prove malformed renamed data never reaches its subscriber.
Completion is saved in this browser only. It does not measure mastery.