TypeDrop
2026-06-01 Challenge
2026-06-01
Hard
Typed Real-Time Event Stream Aggregator
You're building the ingestion layer for a live operations monitoring platform. Raw telemetry events arrive as `unknown` over a simulated stream; your engine must validate them into a discriminated-union event type, route them through per-kind typed reducer functions, enforce a sliding time-window deduplication strategy, and produce a strongly-typed per-source aggregation report — with zero `any`.
Goals
- Define branded scalar types and a discriminated-union TelemetryEvent with per-kind payload shapes.
- Implement a runtime validator that narrows unknown → TelemetryEvent | null without any casts until all checks pass.
- Build a generic AccumulatorMap mapped type and three pure typed reducer functions dispatched exhaustively by event kind.
- Implement a sliding-window deduplicator closure and wire everything together in aggregateStream to produce a fully-typed AggregationReport.
challenge.ts
// Key types & main function signature
type Brand<Base, Tag extends string> = Base & { readonly __brand: Tag };
type EventId = Brand<string, "EventId">;
type SourceId = Brand<string, "SourceId">;
type Timestamp = Brand<number, "Timestamp">;
type TelemetryEvent =
| { kind: "metric"; id: EventId; sourceId: SourceId; timestamp: Timestamp; payload: MetricPayload }
| { kind: "log"; id: EventId; sourceId: SourceId; timestamp: Timestamp; payload: LogPayload }
| { kind: "alert"; id: EventId; sourceId: SourceId; timestamp: Timestamp; payload: AlertPayload };
type AccumulatorMap = {
metric: MetricAccumulator;
log: LogAccumulator;
alert: AlertAccumulator;
};
interface AggregationReport {
sources: Map<SourceId, SourceReport>;
totalIngested: number;
totalDropped: number;
}
function aggregateStream(
rawEvents: unknown[],
dedupConfig: DeduplicationConfig
): AggregationReport { /* TODO */ }
Hints (click to reveal)
Hints
- For AccumulatorMap, a simple interface-based mapped type `{ [K in TelemetryEvent["kind"]]: ... }` plus a conditional type avoids any index-signature tricks.
- In aggregateStream, write a small `applyReducer(report: SourceReport, event: TelemetryEvent): void` helper that switches on `event.kind` — TypeScript will narrow both the event and the accumulator type inside each branch without needing casts.
- The `satisfies` operator in parseEvent lets you build the return object as a plain literal and have the compiler verify the discriminated-union shape in one shot, rather than asserting types piecemeal.
Useful resources
Or clone locally
git clone -b challenge/2026-06-01 https://github.com/niltonheck/typedrop.git