TypeDrop
2026-10-10 Challenge
2026-10-10
Hard
Typed Middleware Pipeline with Context Narrowing
You're building the request-processing core of an API gateway. Incoming requests flow through a chain of middleware — authentication, authorization, validation, and enrichment — each step narrowing or extending a shared context object. The compiler must enforce that each middleware receives exactly the context its predecessor produced, that enrichments accumulate correctly, and that the final handler only runs when the fully-enriched context is provably present.
Goals
- Define the `Middleware<In, Out, E>` type alias and the recursive `MiddlewareTuple<Steps>` conditional type that validates adjacent input/output context compatibility across the tuple.
- Implement `FinalCtx<Steps>` and `InitialCtx<Steps>` helper types that extract the output context of the last middleware and the input context of the first middleware, respectively.
- Implement `createPipeline` with correct generics so that the compiler infers the full pipeline's input and output types — rejecting incompatible middleware orderings at compile time.
- Implement the three concrete middleware (`parseTokenMiddleware`, `verifyTokenMiddleware`, `loadUserMiddleware`) and wire them into `authPipeline`, verifying all five test harness assertions pass.
challenge.ts
// Core middleware type and pipeline result
type Middleware<In, Out, E> = (ctx: In) => Promise<MiddlewareResult<Out, E>>;
type MiddlewareResult<Out, E> =
| { kind: "next"; ctx: Out }
| { kind: "halt"; error: E };
type PipelineResult<Ctx, E> =
| { outcome: "success"; ctx: Ctx }
| { outcome: "halted"; error: E };
// Pipeline factory — your job is to fill in the generics!
function createPipeline<Steps extends ...>(
steps: MiddlewareTuple<Steps>
): {
run: (initialCtx: InitialCtx<Steps>) => Promise<PipelineResult<FinalCtx<Steps>, PipelineError>>
}
Hints (click to reveal)
Hints
- For `MiddlewareTuple`, recurse over the tuple with a helper that checks `Middleware<PrevOut, NextIn, E>` compatibility — use `infer` to extract `In` and `Out` from each element and a conditional to ensure `PrevOut extends NextIn`.
- To extract the last element's output type for `FinalCtx`, use a recursive conditional: `Steps extends [...infer _, infer Last] ? Last extends Middleware<infer _In, infer Out, infer _E> ? Out : never : never`.
- `createPipeline`'s runtime implementation can treat the steps array as `Middleware<unknown, unknown, PipelineError>[]` internally — the type-level constraints live entirely in the generic signature, so the body only needs to thread `ctx` through sequentially.
Useful resources
Or clone locally
git clone -b challenge/2026-10-10 https://github.com/niltonheck/typedrop.git