TypeDrop
2026-05-09 Challenge
2026-05-09
Hard
Typed Streaming ETL Pipeline
You're building the data-ingestion layer for a real-time analytics platform. Raw event batches arrive as `unknown` from multiple upstream sources; your pipeline must validate them, transform each event through a typed middleware chain, fan-out to per-topic async sinks with a concurrency limit, and return a strongly-typed pipeline execution report — with zero `any`.
Goals
- Implement `makeEventId`, `makeTopicName`, and `makeSourceId` using a `Result`-returning branded-type constructor — no `as` or `any` allowed.
- Define `MiddlewareChain<MS>` as a recursive conditional type that resolves to the final output payload type when every adjacent middleware pair is compatible, and `never` otherwise.
- Implement `validateEvent`, `runMiddlewares`, and `fanOutToSinks` so that validation, sequential middleware execution with short-circuit, and concurrency-limited sink fan-out all work correctly.
- Wire everything together in `runPipeline` to produce a fully accurate `PipelineReport` with correct counts and per-topic breakdown.
challenge.ts
// Key types and main entry point — challenge.ts (preview)
type Brand<T, B extends string> = T & { readonly __brand: B };
export type EventId = Brand<string, "EventId">;
export type TopicName = Brand<string, "TopicName">;
export type Result<T, E> =
| { readonly ok: true; readonly value: T }
| { readonly ok: false; readonly error: E };
export type Middleware<
TIn extends Record<string, unknown>,
TOut extends Record<string, unknown>
> = (event: TransformedEvent<TIn>) => Promise<Result<TransformedEvent<TOut>, PipelineError>>;
// Your job: make this recursive conditional type validate chain compatibility
export type MiddlewareChain<
MS extends readonly Middleware<Record<string, unknown>, Record<string, unknown>>[]
> = /* TODO */ unknown;
export async function runPipeline<Topics extends TopicName>(
rawBatch: ReadonlyArray<unknown>,
config: PipelineConfig<Topics>
): Promise<PipelineReport> {
// TODO — validate → transform → fan-out → report
throw new Error("not implemented");
}
Hints (click to reveal)
Hints
- For `MiddlewareChain`, write a helper type `InferMiddlewareOut<M>` using `infer` to extract the `TOut` type from a single `Middleware<TIn, TOut>`, then recurse over the tuple checking that `InferMiddlewareOut<MS[N]>` extends the `TIn` of `MS[N+1]`.
- To enforce the concurrency limit in `fanOutToSinks` without a library, maintain an in-flight counter and a queue of pending tasks — resolve the next queued task each time an in-flight one completes.
- Branded types can be constructed safely by returning `ok(raw as EventId)` only inside the dedicated `makeEventId` function — this is the one place where a cast is acceptable because the function itself IS the runtime guard.
Useful resources
Or clone locally
git clone -b challenge/2026-05-09 https://github.com/niltonheck/typedrop.git