TypeDrop

2026-03-06 Challenge

2026-03-06 Hard

Typed Real-Time Event Aggregator with Windowed Metrics

You're building the analytics backbone of a live-streaming platform. Raw telemetry events (views, reactions, chat messages, errors) arrive in bursts and must be funnelled through a strongly-typed aggregation pipeline that groups them into fixed time windows, computes per-event-kind statistics, and surfaces a typed Result for every query — all with zero `any`.

Goals

  • Define `EventMetrics<K extends EventKind>` as a conditional or mapped type that resolves to the exact metrics interface for each event kind.
  • Implement `EventAggregator` — ingest events into fixed time windows, compute per-kind metrics, and surface typed Results for window queries and range queries.
  • Implement the generic `getMetricsForKind<K>` so TypeScript infers `EventMetrics<K>` at the call site without any type assertions.
  • Implement `renderMetrics` with an exhaustive switch over `EventKind` using `assertNever`, so adding a new kind to the union is a compile-time error.
challenge.ts

// Key types and main class signature

type EventKind = "view" | "reaction" | "chat" | "error";

// TODO: define this conditional/mapped type
type EventMetrics<K extends EventKind> = never; // ← replace

interface WindowSnapshot {
  windowId: WindowId;
  startTs: TimestampMs;
  endTs: TimestampMs;
  metrics: { [K in EventKind]?: EventMetrics<K> };
}

type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };

type AggregatorError =
  | { kind: "EMPTY_WINDOW";    windowId: WindowId }
  | { kind: "WINDOW_NOT_FOUND"; windowId: WindowId }
  | { kind: "INVALID_RANGE";   startTs: TimestampMs; endTs: TimestampMs };

class EventAggregator {
  constructor(private readonly windowSizeMs: number) {}
  ingest(events: readonly TelemetryEvent[]): void { ... }
  computeWindow(windowId: WindowId): Result<WindowSnapshot, AggregatorError> { ... }
  queryRange(startTs: TimestampMs, endTs: TimestampMs): Result<WindowSnapshot[], AggregatorError> { ... }
  getMetricsForKind<K extends EventKind>(windowId: WindowId, kind: K): Result<EventMetrics<K>, AggregatorError> { ... }
}
Hints (click to reveal)

Hints

  • For `EventMetrics<K>`, a conditional type chain (`K extends 'view' ? ViewMetrics : K extends 'reaction' ? ...`) is the cleanest approach — TypeScript can then narrow the return type of `getMetricsForKind` without casts.
  • Inside `getMetricsForKind`, index `snapshot.metrics[kind]` — because `metrics` is typed as `{ [K in EventKind]?: EventMetrics<K> }`, the lookup already returns `EventMetrics<K> | undefined`, so no assertion is needed.
  • For exhaustiveness in `renderMetrics`, switch over the `kind` key of each metrics entry; the `default` branch should call `assertNever(kind)` where `kind: never`.

Or clone locally

git clone -b challenge/2026-03-06 https://github.com/niltonheck/typedrop.git