TypeDrop

2026-04-29 Challenge

2026-04-29 Easy

Typed Shopping Cart Aggregator

You're building the order summary engine for an e-commerce storefront. Raw cart payloads arrive as `unknown` from a client-side checkout form; your engine must validate them, compute per-line totals with applied discounts, and return a strongly-typed order summary — with zero `any`.

Goals

  • Define `Discount`, `CartItem`, `LineTotal`, `OrderSummary`, `CartValidationError`, and `CartResult` types as specified in the requirements.
  • Implement `applyDiscount` using exhaustive discriminated-union narrowing on `Discount`, clamping the result to a minimum of 0.
  • Implement `parseCartItem` to validate an `unknown` value into a `CartItem`, throwing a typed `CartValidationError` on any invalid field.
  • Implement `processCart` to parse an `unknown` array, aggregate line totals into an `OrderSummary`, and return a `CartResult` discriminated union.
challenge.ts
// Core types and main function signature

type Discount =
  | { kind: "percentage"; rate: number }   // e.g. 0.1 = 10%
  | { kind: "fixed"; amount: number };     // absolute deduction per item

type CartItem = {
  id: string;
  name: string;
  quantity: number;        // positive integer
  unitPrice: number;       // >= 0
  discount?: Discount;
};

type CartResult =
  | { kind: "success"; summary: OrderSummary }
  | { kind: "error"; error: CartValidationError };

// Validate an unknown payload and produce a typed order summary
function processCart(raw: unknown): CartResult { /* TODO */ }
Hints (click to reveal)

Hints

  • Use a `switch` on `discount.kind` (or `if`/`else` with narrowing) inside `applyDiscount` — TypeScript will enforce exhaustiveness if you add a `never` check in the default branch.
  • In `parseCartItem`, narrow `raw` step-by-step: first check `typeof raw === 'object' && raw !== null`, then use `'id' in raw` guards before accessing properties — no `as` needed.
  • The `CartValidationError` you throw inside `parseCartItem` is a plain object, not an `Error` instance — catch it in `processCart` and check its `kind` to wrap it in a `CartResult`.

Or clone locally

git clone -b challenge/2026-04-29 https://github.com/niltonheck/typedrop.git