TypeDrop

A new TypeScript challenge every day. Sharpen your types.

TypeDrop delivers a fresh TypeScript challenge every day, generated by AI. Pick a challenge, open it in StackBlitz (preferred) or CodeSandbox (or clone it locally), and make the tests pass. No accounts, no setup — just you and the type system.

Learn more on GitHub →

2026-08-18 Medium

Typed Concurrent Task Scheduler with Priority Queues & Result Aggregation

You're building the background job runner for a data-pipeline platform. Tasks arrive with different priorities and async work functions; the scheduler must run at most N tasks concurrently, drain them in priority order, and return a strongly-typed aggregated report — successes, failures, and per-task durations — without ever widening to `unknown` unsafely or swallowing errors silently.

Goals

  • Implement `makeConcurrency` to produce a branded `Concurrency` type, throwing `TypeError` for invalid inputs.
  • Implement `sortByPriority` to return a stable-sorted copy of tasks using `PRIORITY_WEIGHT`, without mutating the input.
  • Implement the `isSuccess` type predicate to correctly narrow `TaskResult<T>` to `TaskSuccess<T>`.
  • Implement `runScheduler` to execute tasks concurrently up to the given limit, in priority order, capturing both successes and failures, and returning a fully-typed `SchedulerReport<T>` with correct `topResult` tie-breaking.
challenge.ts

// Key types & main function signature at a glance

type Priority = "critical" | "high" | "normal" | "low";

interface Task<T> {
  readonly id: string;
  readonly priority: Priority;
  readonly run: () => Promise<T>;
}

type TaskSuccess<T> = { status: "fulfilled"; id: string; priority: Priority;
                        value: T; durationMs: number };
type TaskFailure    = { status: "rejected";  id: string; priority: Priority;
                        reason: unknown; durationMs: number };
type TaskResult<T>  = TaskSuccess<T> | TaskFailure;

type SchedulerReport<T> = {
  readonly results:          ReadonlyArray<TaskResult<T>>;
  readonly totalDurationMs:  number;
  readonly successCount:     number;
  readonly failureCount:     number;
  readonly topResult:        TaskSuccess<T> | null;
};

// Branded positive-integer concurrency limit
type Concurrency = Brand<number, "Concurrency">;

async function runScheduler<T>(
  tasks: ReadonlyArray<Task<T>>,
  concurrency: Concurrency
): Promise<SchedulerReport<T>>
Hints (click to reveal)

Hints

  • For the concurrency pool in `runScheduler`, maintain a Set of in-flight Promises and use a recursive 'start-next' helper — each time a slot frees up, pull the next task from the sorted queue.
  • To satisfy requirement 4h (original-index tie-breaking for `topResult`), tag each task with its original array index before sorting, then use that index when comparing successes of equal priority.
  • A type predicate function has the return type `result is TaskSuccess<T>` — the compiler will use this to automatically narrow the union inside `if` blocks and `.filter()` calls.

Or clone locally

git clone -b challenge/2026-08-18 https://github.com/niltonheck/typedrop.git