API reference / @evolu/common / Task / MaybeAsync

Type Alias: MaybeAsync<T>

type MaybeAsync<T> = T | PromiseLike<T>;

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

Represents a value that can be either synchronous or asynchronous.

This type is useful for functions that may complete synchronously or asynchronously depending on runtime conditions (e.g., cache hit vs network fetch).

Why MaybeAsync?

When a function can be sync or async, the typical approaches are:

  1. Always return Promise - Simple but forces microtask overhead even for sync values (see "await always adds microtask" test in Task.test.ts)
  2. Use callbacks - Can avoid microtask, but calling code must still await for sane composition, which adds microtask anyway
  3. Return T | PromiseLike<T> - Calling code can check the value and only await when needed, avoiding microtask overhead for sync cases

The third approach (MaybeAsync) provides:

  • Performance: No microtask overhead for synchronous operations
  • Reliability: No interleaving via microtask queue when operations are synchronous, reducing need for mutexes to protect shared state

Example

// Function that may be sync or async
const getData = (id: string): MaybeAsync<Data> => {
  const cached = cache.get(id);
  if (cached) return cached; // Sync path
  return fetchData(id); // Async path
};

// Caller can optimize based on actual behavior
const result = getData(id);
const data = isAsync(result) ? await result : result;

Alternative Approaches

It's possible to eliminate the sync/async distinction using complex frameworks with custom schedulers. However, such frameworks require depending on other people's code that controls how your code executes, resulting in more complex stack traces and debugging experiences. With MaybeAsync, we don't need that machinery - it works directly with JavaScript's native primitives and TypeScript's type system.

TODO: Consider

Use MaybeAsync in Task and Task helpers to preserve synchronous execution when possible (e.g., mutex with available permit, retry on first success).

Type Parameters

Type Parameter
T

Was this page helpful?