TypeDrop

2026-06-24 Challenge

2026-06-24 Easy

Typed Shopping Cart with Discount Rules & Order Summary

You're building the checkout layer for a small e-commerce storefront. Cart items and discount codes arrive as raw input; your module must validate them into strongly-typed structures, apply the correct discount strategy, and return a fully-typed order summary — with zero `any`.

Goals

  • Define a `CartItem` type and a three-variant `Discount` discriminated union with no `any`.
  • Implement `validateCartItem` that narrows `unknown` to `CartItem` and throws a descriptive error for invalid input.
  • Implement `applyDiscount` with an exhaustive switch over all three `Discount` kinds (percentage, fixed, bogo).
  • Implement `buildOrderSummary` that validates raw items, computes the subtotal, applies an optional discount, and returns a fully-typed `OrderSummary`.
challenge.ts
export type ProductCategory = "electronics" | "clothing" | "food" | "books" | "toys";

export type CartItem = {
  id: string;
  name: string;
  priceUSD: number;
  quantity: number;
  category: ProductCategory;
};

export type Discount =
  | { kind: "percentage"; code: string; percent: number }
  | { kind: "fixed";      code: string; amountUSD: number }
  | { kind: "bogo";       code: string; category: ProductCategory };

export type OrderSummary = {
  items: CartItem[];
  subtotalUSD: number;
  discountUSD: number;
  totalUSD: number;
  appliedCode: string | null;
};

export function validateCartItem(raw: unknown): CartItem { /* TODO */ }
export function applyDiscount(items: CartItem[], discount: Discount): number { /* TODO */ }
export function buildOrderSummary(rawItems: unknown[], discount: Discount | null): OrderSummary { /* TODO */ }
Hints (click to reveal)

Hints

  • Use a `switch (discount.kind)` in `applyDiscount` — TypeScript will narrow each branch automatically, and the compiler will warn you if a case is missing.
  • In `validateCartItem`, first check `typeof raw === 'object' && raw !== null`, then use `'id' in raw` guards before accessing individual properties — no `as` needed.
  • For the bogo calculation, group clothing items by category first, then for every pair of quantity count the cheaper item's price as saved — remember quantity means multiple units of one line item.

Or clone locally

git clone -b challenge/2026-06-24 https://github.com/niltonheck/typedrop.git