API reference@evolu/commonTask › allSettled

Call Signature

function allSettled<TTasks>(
  tasks: TTasks,
  options?: TaskCollectionOptions,
): Task<
  InferTasksSettled<TTasks>,
  never,
  ParameterIntersection<
    TTasks[number] extends TTask
      ? TTask extends AnyTask
        ? (deps: InferTaskDeps<TTask>) => void
        : never
      : never
  >
>;

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

Runs all Tasks and returns every Task Result.

Unlike all, Err Results do not stop later Tasks.

With a mapping function, maps input values to Tasks before running them. The mapper runs immediately when allSettled is called, before the returned Task starts. Array mappers receive (value, index). Record mappers receive (value, key). Mapper defects happen at construction time, so keep mappers pure and cheap.

Sequential by default; pass a concurrency option to run more than one Task at a time.

Similar to Promise.allSettled, but runs Tasks and returns Result values.

Example

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

interface LoadError {
  readonly type: "LoadError";
}

const loadProfile: Task<string, LoadError> = () => err({ type: "LoadError" });
let activityLoaded = false;
const loadActivity: Task<ReadonlyArray<string>> = () => {
  activityLoaded = true;
  return ok(["signed-in"]);
};

await using run = createRun();
const results = await run(allSettled([loadProfile, loadActivity]));
expectTypeOf(results).toEqualTypeOf<
  Result<readonly [Result<string, LoadError>, Result<ReadonlyArray<string>>]>
>();
expectOk(results, [
  { ok: false, error: { type: "LoadError" } },
  { ok: true, value: ["signed-in"] },
]);
// Unlike all, a later Task still runs after an Err.
expect(activityLoaded).toBe(true);

Call Signature

function allSettled<TTasks>(
  tasks: TTasks,
  options?: TaskCollectionOptions,
): Task<
  InferTasksSettled<TTasks>,
  never,
  ParameterIntersection<
    TTasks[keyof TTasks] extends TTask
      ? TTask extends AnyTask
        ? (deps: InferTaskDeps<TTask>) => void
        : never
      : never
  >
>;

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

Runs a Task record and preserves its keys.

Example

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

interface User {
  readonly id: string;
}
interface LoadError {
  readonly type: "LoadError";
}
const fetchUser: Task<User> = () => ok({ id: "user-1" });
const fetchProfile: Task<string, LoadError> = () => err({ type: "LoadError" });

await using run = createRun();
const results = await run(
  allSettled({ user: fetchUser, profile: fetchProfile }),
);

expectTypeOf(results).toEqualTypeOf<
  Result<{
    readonly user: Result<User>;
    readonly profile: Result<string, LoadError>;
  }>
>();
expectOk(results, {
  user: { ok: true, value: { id: "user-1" } },
  profile: { ok: false, error: { type: "LoadError" } },
});

Call Signature

function allSettled<TValues, TTask>(
  values: TValues,
  fn: (value: TValues[number], index: number) => TTask,
  options?: TaskCollectionOptions,
): Task<
  {
    readonly [K in string | number | symbol]: Result<
      InferTaskOk<TTask>,
      InferTaskErr<TTask>
    >;
  },
  never,
  ParameterIntersection<
    TTask extends TTask
      ? TTask extends AnyTask
        ? (deps: InferTaskDeps<TTask>) => void
        : never
      : never
  >
>;

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

Maps an array to Tasks and preserves its shape.

Example

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

interface User {
  readonly id: string;
}
interface LoadError {
  readonly type: "LoadError";
}
const loadUser =
  (id: string): Task<User, LoadError> =>
  () =>
    id === "missing" ? err({ type: "LoadError" }) : ok({ id });

const userIds = ["user-1", "missing"] as const;
const indexes: Array<number> = [];
const loadUsers = allSettled(userIds, (id, index) => {
  indexes.push(index);
  return loadUser(id);
});

// Mapping is eager: it happens before the returned Task starts.
expect(indexes).toEqual([0, 1]);

await using run = createRun();
const results = await run(loadUsers);
expectTypeOf(results).toEqualTypeOf<
  Result<readonly [Result<User, LoadError>, Result<User, LoadError>]>
>();
expectOk(results, [
  { ok: true, value: { id: "user-1" } },
  { ok: false, error: { type: "LoadError" } },
]);

Call Signature

function allSettled<TValues, TTask>(
  values: TValues,
  fn: (value: TValues[keyof TValues], key: keyof TValues) => TTask,
  options?: TaskCollectionOptions,
): Task<
  {
    readonly [K in string | number | symbol]: Result<
      InferTaskOk<TTask>,
      InferTaskErr<TTask>
    >;
  },
  never,
  ParameterIntersection<
    TTask extends TTask
      ? TTask extends AnyTask
        ? (deps: InferTaskDeps<TTask>) => void
        : never
      : never
  >
>;

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

Maps record values to Tasks and preserves its keys.

Example

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

interface User {
  readonly id: string;
}
interface LoadError {
  readonly type: "LoadError";
}
const loadUser =
  (id: string): Task<User, LoadError> =>
  () =>
    id === "missing" ? err({ type: "LoadError" }) : ok({ id });

const userIdsByRole = { admin: "user-1", reviewer: "missing" } as const;
const roles: Array<keyof typeof userIdsByRole> = [];
const loadUsersByRole = allSettled(userIdsByRole, (id, role) => {
  roles.push(role);
  return loadUser(id);
});

// Mapping is eager: it happens before the returned Task starts.
expect(roles).toEqual(["admin", "reviewer"]);

await using run = createRun();
const results = await run(loadUsersByRole);
expectTypeOf(results).toEqualTypeOf<
  Result<{
    readonly admin: Result<User, LoadError>;
    readonly reviewer: Result<User, LoadError>;
  }>
>();
expectOk(results, {
  admin: { ok: true, value: { id: "user-1" } },
  reviewer: { ok: false, error: { type: "LoadError" } },
});