TypeDrop
2026-07-03 Challenge
2026-07-03
Medium
Typed Job Queue Scheduler with Priority & Retry Policies
You're building the background job scheduling engine for a distributed task platform. Raw job definitions arrive as `unknown` from a message broker; your engine must validate them into strongly-typed `Job` records, schedule them according to priority tiers, apply per-job-type retry policies, and return a fully-typed dispatch plan — with zero `any`.
Goals
- Implement `validateJob` to parse `unknown` broker messages into strongly-typed `Job` records, collecting all field-level errors before returning.
- Implement `getInitialDelayMs` whose return type is derived from the `PriorityDelayMs<P>` conditional type — no plain `number` annotation allowed.
- Implement `buildDispatchPlan` to validate all raw inputs, sort valid jobs by priority DESC then enqueuedAt ASC, and populate the `rejected` map with index-keyed errors.
- Implement `filterByKind` and `isPayloadOfKind` so that filtered entries have their `job.payload` narrowed to the exact `Extract<JobPayload, { kind: K }>` variant — verified at compile time.
challenge.ts
// Key types and main function signatures
export type Priority = 1 | 2 | 3;
export type JobKind = "email" | "report" | "export" | "webhook";
export type JobPayload =
| { kind: "email"; to: string; subject: string; body: string }
| { kind: "report"; reportId: string; format: "pdf" | "csv" }
| { kind: "export"; resourceType: string; filters: Record<string, string> }
| { kind: "webhook"; url: string; secret: string };
export type JobId = string & { readonly __brand: "JobId" };
export type PriorityDelayMs<P extends Priority> =
P extends 3 ? 0 : P extends 2 ? 500 : 2000;
// Validate one raw broker message → typed Job or collected errors
export function validateJob(
raw: unknown,
retryPolicies: RetryPolicyMap
): Result<Job, ValidationError[]> { /* TODO */ }
// Derive first-attempt delay from priority via conditional type
export function getInitialDelayMs<P extends Priority>(priority: P): PriorityDelayMs<P> { /* TODO */ }
// Build a fully-typed dispatch plan from raw broker messages
export function buildDispatchPlan(
rawJobs: unknown[],
retryPolicies: RetryPolicyMap
): DispatchPlan { /* TODO */ }
// Narrow a DispatchPlan to entries of a specific job kind
export function filterByKind<K extends JobKind>(
plan: DispatchPlan, kind: K
): NarrowedEntry<K>[] { /* TODO */ }
Hints (click to reveal)
Hints
- For `validateJob`, check `typeof raw === 'object' && raw !== null` first, then use `'field' in raw` guards to safely access each property — this satisfies strict mode without `as`.
- For `getInitialDelayMs`, a lookup object `const delays = { 1: 2000, 2: 500, 3: 0 } as const` combined with `return delays[priority]` satisfies the conditional return type — think about how `as const` interacts with index signatures.
- For `filterByKind`, call `isPayloadOfKind` inside `.filter()` — TypeScript will propagate the type predicate into the narrowed array, letting you cast the result to `NarrowedEntry<K>[]` cleanly.
Useful resources
Or clone locally
git clone -b challenge/2026-07-03 https://github.com/niltonheck/typedrop.git