TypeDrop

2026-10-19 Challenge

2026-10-19 Easy

Typed Shopping Cart Reducer

You're building the cart logic for a lightweight e-commerce checkout flow. Cart actions arrive as a discriminated union, and a pure reducer must apply each action to produce a new typed cart state — the compiler must enforce that every action variant carries exactly the right payload and that the derived totals always stay in sync.

Goals

  • Define CartItem, CartState, and a four-variant CartAction discriminated union with correctly typed payloads.
  • Implement cartReducer as a pure function that handles all four action types and keeps totals in sync.
  • Use Omit<CartItem, 'quantity'> for the ADD_ITEM payload and Pick<CartState, ...> for the computeTotals return type.
  • Add an exhaustive default branch using a never variable so the compiler catches any unhandled action variant.
challenge.ts

// Core types you must define:
export type CartItem = {
  id: string;
  name: string;
  priceInCents: number;
  quantity: number;
};

export type CartState = {
  items: CartItem[];
  totalItems: number;
  totalPriceInCents: number;
};

// Four-variant discriminated union (yours to complete):
export type CartAction = never; // ← replace with your union

// Pure reducer — compiler must catch any unhandled action variant:
export function cartReducer(state: CartState, action: CartAction): CartState {
  // switch on action.type ...
  throw new Error("Not implemented");
}
Hints (click to reveal)

Hints

  • A `never`-typed variable in the default branch (e.g. `const _exhaustive: never = action`) is the idiomatic way to get compile-time exhaustiveness checking in a switch.
  • For ADD_ITEM, search `state.items` for an existing id first — if found, map over items to increment quantity; otherwise spread in a new item with quantity 1.
  • computeTotals only needs a single Array.reduce pass to accumulate both totalItems and totalPriceInCents simultaneously.

Or clone locally

git clone -b challenge/2026-10-19 https://github.com/niltonheck/typedrop.git