TypeDrop
2026-10-27 Challenge
2026-10-27
Medium
Typed Paginated API Client with Result Accumulation
You're building the data-fetching layer for an analytics dashboard that pulls reports from a paginated REST API. The client must walk pages automatically, accumulate results into typed summaries, and surface per-page errors without losing successfully fetched data.
Goals
- Implement `PickRows<R, C>` as a distributive conditional type that filters rows by category.
- Implement `SummaryDisplay` as a mapped type over `ReportCategory` producing a string per key.
- Implement `buildCategorySummary` to aggregate all rows in a single pass, including zero-row categories.
- Implement `fetchAllPages` to sequentially follow page cursors, accumulate rows, record errors, and stop pagination on failure.
challenge.ts
export type ReportCategory = "revenue" | "engagement" | "retention" | "churn";
export interface ReportRow {
id: string;
category: ReportCategory;
value: number;
label: string;
}
export type CategorySummary = Record<
ReportCategory,
{ count: number; totalValue: number; avgValue: number }
>;
export interface FetchAllResult {
rows: ReportRow[];
summary: CategorySummary;
errors: PageError[];
pagesAttempted: number;
}
// Your two utility types:
export type PickRows<R extends { category: string }, C extends string> = never; // TODO A
export type SummaryDisplay = never; // TODO B
// Core function to implement:
export async function fetchAllPages(
fetchPage: FetchPage,
maxPages?: number
): Promise<FetchAllResult> { /* TODO */ throw new Error(); }
Hints (click to reveal)
Hints
- For `PickRows`, a distributive conditional type distributes over unions automatically when the type parameter appears naked on the left side of `extends`.
- For `SummaryDisplay`, use `{ [K in ReportCategory]: string }` rather than `Record<ReportCategory, string>` to satisfy the mapped-type requirement.
- In `fetchAllPages`, a `while (cursor !== null && pagesAttempted < maxPages)` loop with sequential `await` is the cleanest pattern — break out of it when you receive a `PageError`.
Useful resources
Or clone locally
git clone -b challenge/2026-10-27 https://github.com/niltonheck/typedrop.git