TypeDrop
2026-06-09 Challenge
2026-06-09
Medium
Typed Job Queue Scheduler with Priority & Concurrency
You're building the background-job engine for a data-processing platform. Raw job definitions arrive as `unknown` from a REST API; your scheduler must validate them, dispatch jobs by priority through a typed concurrency-limited runner, and return a strongly-typed execution report — with zero `any`.
Goals
- Define a three-variant discriminated union `JobDefinition` and a generic `Result<T, E>` type with no `any`.
- Implement `parseJobDefinition` that narrows `unknown` input to the correct `JobDefinition` variant or returns a descriptive error string.
- Build a `JobHandlerMap` mapped type using `Extract` and implement the concurrency-limited `runScheduler` that sorts jobs by priority and caps parallel execution.
- Ensure `runScheduler` returns a fully-typed `SchedulerReport` that accounts for both parse failures and runtime handler errors.
challenge.ts
// Key types & main function signature
type Priority = "critical" | "high" | "normal" | "low";
// Discriminated union — three variants sharing a `kind` discriminant
type JobDefinition =
| { readonly kind: "http"; readonly id: string; readonly priority: Priority; /* ... */ }
| { readonly kind: "compute"; readonly id: string; readonly priority: Priority; /* ... */ }
| { readonly kind: "notification"; readonly id: string; readonly priority: Priority; /* ... */ };
// Generic Result monad
type Result<T, E> = /* { ok: true; value: T } | { ok: false; error: E } */;
// Mapped type: one async handler per job kind
type JobHandlerMap = {
[K in JobDefinition["kind"]]: (job: Extract<JobDefinition, { kind: K }>) => Promise<void>;
};
// Validates unknown input → typed JobDefinition or error string
function parseJobDefinition(raw: unknown): Result<JobDefinition, string> { /* ... */ }
// Validates, sorts by priority, runs up to `concurrency` jobs in parallel
async function runScheduler(
rawJobs: unknown[],
options: { concurrency: number; handlers: JobHandlerMap }
): Promise<SchedulerReport> { /* ... */ }
Hints (click to reveal)
Hints
- For `JobHandlerMap`, use a mapped type over `JobDefinition["kind"]` combined with `Extract<JobDefinition, { kind: K }>` to get the exact variant type per handler.
- For the concurrency limiter in `runScheduler`, maintain a counter of active jobs and a queue; resolve slots as each job settles — or consider using a Promise pool pattern.
- In `parseJobDefinition`, narrow `kind` with a switch statement first, then validate kind-specific fields inside each case — this keeps TypeScript's narrowing happy without any type assertions.
Useful resources
Or clone locally
git clone -b challenge/2026-06-09 https://github.com/niltonheck/typedrop.git