composeAsync
Composes asynchronous functions from right to left.
1/**
2 * Composes asynchronous functions from right to left.
3 *
4 * @param fns - Functions to compose (right to left).
5 * @returns A function that applies the composed functions to an input.
6 */
7export function composeAsync<T>(
8 ...fns: Array<(input: any) => Promise<any> | any>
9): (input: T) => Promise<any> {
10 return async (input: T): Promise<any> => {
11 let result = input;
12 for (let i = fns.length - 1; i >= 0; i--) {
13 result = await fns[i](result);
14 }
15 return result;
16 };
17}
Supports Mixed Async and Sync Functions
Composes any combination of asynchronous and synchronous functions without extra boilerplate.
Right-to-Left Execution Order
Aligns with traditional composition notation (
f(g(x))
), making it familiar to functional programming users.Robust Promise Handling
Internally uses
await
to handle any type of function return (sync orPromise
), ensuring consistent behavior.Readable and Maintainable
Clear loop-based implementation improves debuggability compared to nested promises or recursive calls.
Tests | Examples
1test('composeAsync - composes two async functions', async () => {
2 const add = async (x: number) => x + 2;
3 const double = async (x: number) => x * 2;
4
5 const composed = composeAsync(add, double);
6 const result = await composed(3);
7
8 expect(result).toBe(8); // double(3) = 6; add(6) = 8
9});
10
11test('composeAsync - handles mixed sync and async functions', async () => {
12 const toStr = (x: number) => `Value: ${x}`;
13 const increment = async (x: number) => x + 1;
14
15 const composed = composeAsync(toStr, increment);
16 const result = await composed(4);
17
18 expect(result).toBe('Value: 5');
19});
20
21test('composeAsync - returns original value when no functions', async () => {
22 const composed = composeAsync();
23 const result = await composed('test');
24
25 expect(result).toBe('test');
26});
Common Use Cases
Async Middleware Composition
Compose multiple middlewares or interceptors in backend frameworks or API handlers.
Data Transformation Pipelines
Build right-to-left pipelines for transforming fetched data, applying validators, or formatting results.
Async Validation Chains
Combine multiple async validation functions for processing forms, payloads, or external input.
Workflow Engines or Task Runners
Dynamically compose async steps for executing multi-stage jobs or ETL pipelines.
Functional Reactive Patterns
Apply composed transformations to observable or event stream data that resolves asynchronously.