API reference@evolu/commonTask › race

function race<TTasks>(
  tasks: TTasks,
): Task<
  InferTaskOk<TTasks[number]>,
  InferTaskErr<TTasks[number]>,
  ParameterIntersection<
    TTasks[number] extends TTask
      ? TTask extends AnyTask
        ? (deps: InferTaskDeps<TTask>) => void
        : never
      : never
  >
>;

Defined in: packages/common/src/Task.ts:4178

Runs Tasks until the first Task settles.

Returns the first Task Result to settle, whether Ok or Err.

Use any to wait for the first Ok instead.

Losing Tasks are aborted.

Tasks always run concurrently because racing sequentially would be meaningless.

Similar to Promise.race, but races Tasks, returns Result values, and aborts losers.

Requires a non-empty array: zero Tasks have no meaningful first settled Result. This is enforced at compile time for non-empty tuple types. For arrays whose emptiness is only known at runtime, guard with isNonEmptyArray:

Example

import { createRun, isNonEmptyArray, ok, race, type Task } from "@evolu/common";

const tasks: ReadonlyArray<Task<string>> = [() => ok("first")];
await using run = createRun();
if (isNonEmptyArray(tasks)) {
  const result = await run(race(tasks));
  expectOk(result, "first");
}

Example

import {
  createRun,
  ok,
  race,
  sleep,
  type Result,
  type Task,
} from "@evolu/common";

await using run = createRun();

const fast: Task<string> = () => ok("fast");
let slowCompleted = false;
const slow: Task<string> = async (run) => {
  await run.ok(sleep("10ms"));
  slowCompleted = true;
  return ok("slow");
};

// Input order does not matter: the first settled Result wins, and the
// still-running loser is aborted.
const result = await run(race([slow, fast]));
expectTypeOf(result).toEqualTypeOf<Result<string>>();
expectOk(result, "fast");
expect(slowCompleted).toBe(false);