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.

Or clone locally

git clone -b challenge/2026-07-23 https://github.com/niltonheck/typedrop.git