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`.
Useful resources
Or clone locally
git clone -b challenge/2026-03-06 https://github.com/niltonheck/typedrop.git