Skip to content

Feature request: call / callAsync #1659

@zrosenbauer

Description

@zrosenbauer

Problem

JavaScript has no expression-oriented blocks. When computing a value through conditionals or multiple steps, you're stuck with either mutable let bindings or IIFEs:

// Mutable — result is `let` for the rest of the scope
let result: string;
if (user.role === "admin") {
  result = formatPerms(await fetchAdminPerms(user.id));
} else {
  result = "none";
}

// IIFE — noisy, hard to scan
const result = (async () => {
  if (user.role === "admin") return formatPerms(await fetchAdminPerms(user.id));
  return "none";
})();

IIFEs are widely considered a code smell in modern JavaScript:

Examples in other languages

Language Feature Example
Kotlin run { } val x = run { ... }
Rust Block expressions let x = { ... };
Scala Block expressions val x = { ... }
Ruby Inline blocks x = begin ... end

Proposal

// Sync
const result = call(() => {
  if (user.role === "admin") return "full";
  if (user.role === "editor") return "partial";
  return "none";
});

// Async
const result = await callAsync(async () => {
  const perms = await fetchPerms(user.id);
  const roles = await fetchRoles(user.id);
  return merge(perms, roles);
});

Implementation:

export function call<R>(fn: () => R): R {
  return fn();
}

export async function callAsync<R>(fn: () => Promise<R>): Promise<R> {
  return await fn();
}

The implementation is trivial — but so are noop, identity, and attempt. The value is naming the pattern, not the complexity of the code. call(() => ...) communicates intent where (() => ...)() hides it in punctuation.

Precedent

es-toolkit already wraps simple patterns into named utilities:

  • attempt(fn) — wraps try/catch
  • noop() — wraps () => {}
  • identity(x) — wraps (x) => x

call(fn) fits the same category.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions