TypeDrop
2026-07-23 Challenge
2026-07-23
Easy
Typed GroupBy & Aggregation Pipeline
You're building the reporting layer for a sales dashboard. Raw transaction records need to be bucketed by an arbitrary key, then summarised with typed aggregation functions — all without losing the shape of the original data or reaching for `any`.
Goals
- Implement `groupBy` using a generic `Map<K, T[]>` where `K extends Keyable`, correctly bucketing items by their computed key.
- Implement `aggregateGroups` to transform a `Grouped<K, T>` into `GroupSummary<K, S>[]` by applying a typed `summarise` reducer to each bucket.
- Implement `groupAndAggregate` as a single-call pipeline that composes the two functions above with fully inferred generic parameters.
- Implement `topN` to return the highest-scoring `n` summaries in descending order without mutating the input array.
challenge.ts
/** A record whose values can be safely used as Map keys. */
type Keyable = string | number | boolean;
/** Each distinct key maps to the subset of items that share it. */
type Grouped<K extends Keyable, T> = Map<K, T[]>;
/** One aggregated summary entry produced from a single group. */
type GroupSummary<K extends Keyable, S> = {
key: K;
summary: S;
};
// Group items by an arbitrary key —————————————————————————————
declare function groupBy<T, K extends Keyable>(
items: T[],
keySelector: (item: T) => K
): Grouped<K, T>;
// Reduce each group to a typed summary ————————————————————————
declare function aggregateGroups<K extends Keyable, T, S>(
grouped: Grouped<K, T>,
summarise: (items: T[]) => S
): GroupSummary<K, S>[];
// Pipeline convenience: group + aggregate in one call —————————
declare function groupAndAggregate<T, K extends Keyable, S>(
items: T[],
keySelector: (item: T) => K,
summarise: (items: T[]) => S
): GroupSummary<K, S>[];
// Return the top-n summaries ranked by a numeric score ————————
declare function topN<K extends Keyable, S>(
summaries: GroupSummary<K, S>[],
score: (summary: S) => number,
n: number
): GroupSummary<K, S>[];
Hints (click to reveal)
Hints
- The `Grouped` type is just a `Map` — reach for `Map.get`, `Map.set`, and `Map.entries()` / `for...of` to iterate it without losing key types.
- For `topN`, spreading the array before sorting (`[...summaries]`) keeps the original intact and satisfies the no-mutation requirement.
- `groupAndAggregate` can be a one-liner that delegates entirely to `groupBy` and `aggregateGroups` — TypeScript will infer all three type parameters from the arguments.
Useful resources
Or clone locally
git clone -b challenge/2026-07-23 https://github.com/niltonheck/typedrop.git