TypeDrop
2026-06-18 Challenge
2026-06-18
Hard
Typed GraphQL-Style Query Planner & Resolver
You're building the query execution layer for an in-house data-graph API. Raw query documents arrive as `unknown` from an HTTP body; your planner must validate them, resolve each field through a registry of strongly-typed resolvers, fan out leaf fetches concurrently with a concurrency cap, and return a deeply-typed response tree — with zero `any`.
Goals
- Implement `validateQueryDocument` to safely narrow an `unknown` HTTP body into a typed `QueryDocument` using structural type guards — no `any`, no assertions.
- Implement `buildExecutionPlan` to convert a `QueryDocument` into a recursive `ExecutionPlan` tree where every node carries a correctly-constructed branded `ResolverPath`.
- Implement `createConcurrencyLimiter` as a generic queue-based scheduler that caps simultaneous async tasks while preserving each task's return type.
- Implement `executeQuery` to fan out root resolvers concurrently (or sequentially for mutations), resolve children with parent values, isolate per-field errors, and assemble a `QueryResponse`.
challenge.ts
// Key types at a glance:
type ScalarValue = string | number | boolean | null;
type ResponseNode =
| ScalarValue
| ResponseNode[]
| { [field: string]: ResponseNode };
declare const __resolverPath: unique symbol;
type ResolverPath = string & { readonly [__resolverPath]: true };
type ResolverRegistry = Map<ResolverPath, Resolver>;
interface ExecutionPlan {
operation: "query" | "mutation";
roots: PlanNode[]; // PlanNode.children is recursive
}
// --- Main entry point you must implement ---
async function runQuery(
raw: unknown, // straight from HTTP body
registry: ResolverRegistry,
context: ResolverContext
): Promise<QueryResponse>;
// pipeline: validate → buildExecutionPlan → executeQuery
Hints (click to reveal)
Hints
- For `createConcurrencyLimiter`, maintain a counter of running tasks and a queue of `() => void` drain callbacks — resolve each queued promise only when a slot opens.
- In `validateQueryDocument`, write a recursive `isFieldSelection(v: unknown): v is FieldSelection` guard; TypeScript will narrow the array element type for you if you use `Array.prototype.every`.
- In `executeQuery`, remember that `mutation` root nodes must run one-at-a-time: use a `for...of` loop with `await` instead of `Promise.all`, even when the concurrency limiter is active.
Useful resources
Or clone locally
git clone -b challenge/2026-06-18 https://github.com/niltonheck/typedrop.git