TypeDrop
2026-03-08 Challenge
2026-03-08
Easy
Typed Inventory Aggregator
You're building the stock-management module for an e-commerce back-office. Raw inventory records arrive from multiple warehouses and must be validated, grouped by category, and summarised — all with zero `any` and fully typed results.
Goals
- Implement `validateRecord` to narrow a `RawRecord` into an `InventoryItem` or return a typed `ValidationError` using a `Result` discriminated union.
- Implement `partitionRecords` to collect all valid items and all errors in a single pass without short-circuiting.
- Implement `aggregateByCategory` to group items and compute per-category statistics (`totalItems`, `totalQuantity`, `totalValue`, `averageUnitPrice`) in a single loop.
- Compose the full pipeline in `processInventory`, returning both the aggregated summary and any validation errors.
challenge.ts
// Key types & main signatures at a glance
export type Category = "electronics" | "clothing" | "food" | "furniture";
export type Result<T, E> =
| { ok: true; value: T }
| { ok: false; error: E };
export interface InventoryItem extends Omit<RawRecord, "category"> {
category: Category; // narrowed from raw string
}
export interface CategorySummary {
category: Category;
totalItems: number;
totalQuantity: number;
totalValue: number; // sum of quantity * unitPrice (cents)
averageUnitPrice: number; // rounded mean unitPrice across SKUs
}
// ── Functions you must implement ──────────────────────────────────────────────
export function validateRecord(raw: RawRecord): Result<InventoryItem, ValidationError>;
export function partitionRecords(raws: RawRecord[]): { valid: InventoryItem[]; errors: ValidationError[] };
export function aggregateByCategory(items: InventoryItem[]): Partial<Record<Category, CategorySummary>>;
export function processInventory(raws: RawRecord[]): { summary: Partial<Record<Category, CategorySummary>>; errors: ValidationError[] };
Hints (click to reveal)
Hints
- A `Set` or tuple literal like `["electronics", "clothing", "food", "furniture"] as const` makes it easy to check whether a raw string is a valid `Category` — and TypeScript will narrow the type for you after the check.
- For `aggregateByCategory`, use `Array.prototype.reduce` with a `Partial<Record<Category, CategorySummary>>` accumulator so you can build each entry on first encounter and update it on subsequent ones — all in one pass.
- The `Result<T, E>` discriminated union lets you branch on `.ok` without any type assertions — lean on that in `partitionRecords` to route each outcome to the right bucket.
Useful resources
Or clone locally
git clone -b challenge/2026-03-08 https://github.com/niltonheck/typedrop.git