TypeDrop
2026-10-01 Challenge
2026-10-01
Easy
Typed Recipe Ingredient Scaler
You're building the core logic for a recipe app that lets users scale ingredient quantities up or down. Given a recipe with strongly-typed ingredients and units, the app must produce a scaled version with correctly adjusted amounts and a human-readable shopping list — all verified by the compiler.
Goals
- Define `ScaledIngredient` as a utility/mapped type derived from `Ingredient` (no hand-written duplicates).
- Implement `scaleRecipe` to multiply ingredient amounts by the correct factor, round to 2 decimal places, and throw a `RangeError` for invalid servings.
- Implement `toShoppingList` using type narrowing (not casts) to produce the correct discriminated-union `ShoppingListEntry` variant for each ingredient.
- Implement `mergeShoppingLists` using a `Map` to combine entries with the same name AND kind in O(n) time.
challenge.ts
// Key types you'll work with:
type Unit = "tsp" | "tbsp" | "cup" | "oz" | "lb"
| "g" | "kg" | "ml" | "l" | "whole";
interface Ingredient {
readonly name: string;
readonly amount: number;
readonly unit: Unit;
}
// TODO: derive this from Ingredient using a utility type
type ScaledIngredient = never;
interface Recipe {
readonly title: string;
readonly servings: number;
readonly ingredients: readonly Ingredient[];
}
// Main function signatures:
function scaleRecipe(recipe: Recipe, targetServings: number): ScaleResult { ... }
function toShoppingList(ingredients: readonly ScaledIngredient[]): ShoppingListEntry[] { ... }
function mergeShoppingLists(listA: ShoppingListEntry[], listB: ShoppingListEntry[]): ShoppingListEntry[] { ... }
Hints (click to reveal)
Hints
- For `ScaledIngredient`, look at how `Readonly<T>` or a simple mapped type can re-use `Ingredient`'s fields without rewriting them.
- In `toShoppingList`, a plain `if (ingredient.unit === 'whole')` check is enough for TypeScript to narrow the type — no `as` needed.
- For `mergeShoppingLists`, use a composite key like `${entry.name}::${entry.kind}` as your `Map` key to distinguish same-name different-kind entries.
Useful resources
Or clone locally
git clone -b challenge/2026-10-01 https://github.com/niltonheck/typedrop.git