Yevhen Klymentiev
dark
light
console
darkness
y.klymentiev@gmail.com
Reusable Snippets|Practical utility code for everyday use — custom-built and ready to share

pipeAsync

Composes async and sync functions from left to right.

TypeScript
Copied!
1/**
2 * Composes async and sync functions from left to right.
3 *
4 * @param funcs - An array of functions (sync or async).
5 * @returns A function that returns a Promise resolving to the final result.
6 *
7 * @example
8 * const double = async (x: number) => x * 2;
9 * const square = (x: number) => x * x;
10 * const result = await pipeAsync(double, square)(3); // (3 * 2)^2 = 36
11 */
12export function pipeAsync<T>(
13  ...funcs: Array<(arg: any) => any | Promise<any>>
14): (input: T) => Promise<any> {
15  return async (input: T) => {
16    let result = input;
17    for (const fn of funcs) {
18      result = await fn(result);
19    }
20    return result;
21  };
22}
  • Supports Mixed Sync and Async Functions

    Seamlessly composes both synchronous and asynchronous operations into a unified, promise-based pipeline.

  • Left-to-Right Execution Order

    Applies functions in intuitive order, enhancing readability and predictability of data flow.

  • Automatic Promise Handling

    Uses await internally to handle any mix of sync and async return values without requiring external wrapping.

  • Versatile and Flexible

    Accepts any number of unary functions, enabling complex dynamic pipelines for processing streams, data, or user input.

Tests | Examples

TypeScript
Copied!
1test('pipeAsync - applies async and sync functions in order', async () => {
2  const double = async (x: number) => x * 2;
3  const square = (x: number) => x * x;
4  const addOne = async (x: number) => x + 1;
5
6  const fn = pipeAsync(double, square, addOne);
7  const result = await fn(2); // ((2 * 2)^2) + 1 = 17
8  expect(result).toBe(17);
9});
10
11test('pipeAsync - works with only sync functions', async () => {
12  const fn = pipeAsync(
13    (x: string) => x.length,
14    (len: number) => len * 2
15  );
16  const result = await fn('abc'); // 3 * 2 = 6
17  expect(result).toBe(6);
18});
19
20test('pipeAsync - works with only async functions', async () => {
21  const fn = pipeAsync(
22    async (x: number) => x + 1,
23    async (x: number) => x * 3
24  );
25  const result = await fn(2); // (2 + 1) * 3 = 9
26  expect(result).toBe(9);
27});
28
29test('pipeAsync - works with no functions', async () => {
30  const fn = pipeAsync();
31  const result = await fn('test');
32  expect(result).toBe('test');
33});

Common Use Cases

  • Async Data Transformation Pipelines

    Chain API calls, validators, formatters, or enrichment steps in data processing tasks.

  • Form Submission and Validation

    Process user input with sync validators and async sanitizers (e.g. checking uniqueness via API) in one flow.

  • Middleware and Request Handling

    Compose pre-processing steps for HTTP requests or background jobs that involve both local and remote logic.

  • ETL and Workflow Systems

    Build custom steps for Extract–Transform–Load processes where each step may involve IO or computation.

  • Reactive Logic and Event Pipelines

    Process user actions or system events through a pipeline of business logic, validation, and side effects.

Codebase: Utilities -> Functions -> pipeAsync | Yevhen Klymentiev