Capstone: A Typed Store with Branded IDs
Build a small typed state store for a shopping cart. Three pieces: the action type, a reducer, and a generic Store<S, A> class.
CartAction is a union of { type: 'add'; id: ProductId }, { type: 'remove'; id: ProductId } and { type: 'checkout' }. reducer(state, action) returns the new CartState and ends its switch with assertNever(action): add increases the quantity of an existing item or adds one with quantity 1, remove deletes the item, checkout sets the status to 'checkedOut'.
Store<S, A> takes a reducer (state: S, action: A) => S and a starting state. It has getState(), dispatch(action) (run the reducer, then tell every listener) and subscribe(listener), which returns a function that removes the listener. The driver code at the bottom must print items: 1, open, items: 1, open, items: 2, open, items: 1, open, then checkedOut.
Keep the helpers and the driver code. A raw string like "p1" must not be accepted as a ProductId.
What Check tests
- Your code has no type errors
- The driver prints the expected five lines
- A raw string is not a ProductId
- An unknown action is rejected
- The reducer ends in assertNever
- A listener must take the state type
Stuck? One hint at a time
The solution unlocks after your first Check. Try first: that is where the learning happens.
Console
Nothing printed yet.