TypeDrop
2026-05-26 Challenge
2026-05-26
Medium
Typed Event Aggregator with Discriminated Union Streams
You're building the analytics ingestion layer for a real-time monitoring dashboard. Raw telemetry events arrive as `unknown` from a WebSocket feed; your engine must validate them, fan them into typed streams by category, and produce a strongly-typed per-category summary report — with zero `any`.
Goals
- Define `TypedEvent` as a three-member discriminated union and derive `EventCategory`, `EventByCategory<C>`, and `SummaryByCategory<C>` from it using conditional types or `Extract<>` — no hardcoded strings in utility types.
- Implement `validateRawEvent` and `parseEvent` to narrow `unknown` inputs into fully typed events, returning a `ParseResult` discriminated union without any `as` assertions.
- Implement the generic `extractCategory<C>` so that TypeScript statically narrows the returned array element type to the correct `TypedEvent` member for each category.
- Implement the generic `summarize<C>` to compute `ErrorSummary`, `MetricSummary`, or `AuditSummary` with correct aggregation logic (topCode, per-name averages, unique actors), with the return type statically resolving to the right summary via `SummaryByCategory<C>`.
challenge.ts
// Core discriminated union & key types you must define:
export type TypedEvent =
| { category: "error"; id: string; ts: number; payload: ErrorPayload }
| { category: "metric"; id: string; ts: number; payload: MetricPayload }
| { category: "audit"; id: string; ts: number; payload: AuditPayload };
export type EventCategory = TypedEvent["category"]; // derive, don't hardcode
export type EventByCategory<C extends EventCategory> = /* your conditional type */;
export type SummaryByCategory<C extends EventCategory> = /* your conditional type */;
// Main generic functions you must implement:
export function extractCategory<C extends EventCategory>(
results: ParseResult[],
category: C
): EventByCategory<C>[];
export function summarize<C extends EventCategory>(
results: ParseResult[],
category: C
): SummaryByCategory<C>;
Hints (click to reveal)
Hints
- For `EventByCategory<C>`, try `Extract<TypedEvent, { category: C }>` — it resolves to exactly the union member whose `category` matches `C`.
- For `SummaryByCategory<C>`, a conditional type chain `C extends 'error' ? ErrorSummary : C extends 'metric' ? MetricSummary : AuditSummary` is the cleanest approach — but you'll still need a type assertion-free way to return it from `summarize`; consider a type predicate or exhaustive if/else that TypeScript can follow.
- In `validateRawEvent`, use `typeof`, `Array.isArray`, and `Object.keys` checks — never `as`. Once all checks pass, TypeScript will accept the return type.
Useful resources
Or clone locally
git clone -b challenge/2026-05-26 https://github.com/niltonheck/typedrop.git