pipe
The pipe utility performs functional composition from left to right. It takes multiple functions and returns a single function that passes its result from one call to the next, creating a processing pipeline.
Source Code
View Source Code
ts
import type { Fn } from '../types';
import { assert } from './assert';
type FirstParameters<T> = T extends [infer First extends Fn, ...any] ? Parameters<First> : never;
type LastReturnType<T> = T extends [...any, infer Last extends Fn] ? ReturnType<Last> : never;
/**
* Pipes multiple functions into a single function. It starts from the leftmost function and proceeds to the right.
*
* @example
* ```ts
* const add = (x) => x + 2;
* const multiply = (x) => x * 3;
* const subtract = (x) => x - 4;
* const pipedFn = pipe(subtract, multiply, add);
*
* pipedFn(5); // ((5-4) * 3) + 2 = 5
* ```
*
* @param fns - List of functions to be piped.
*
* @returns A new function that is the pipe of the input functions.
*/
export function pipe<T extends Fn[]>(...fns: T): (...args: FirstParameters<T>) => LastReturnType<T> {
assert(fns.length > 0, 'pipe requires at least one function', { args: { fns } });
const [firstFn, ...restFns] = fns;
return ((...args: FirstParameters<T>) => restFns.reduce((prev, fn) => fn(prev), firstFn(...args))) as (
...args: FirstParameters<T>
) => LastReturnType<T>;
}Features
- Isomorphic: Works in both Browser and Node.js.
- Async Support: Automatically handles Promises. If any function in the pipe returns a Promise, the final result will be a Promise.
- Type-safe: Properly infers input and output types through the entire pipeline.
- Left-to-Right: Executes functions in the order they are provided.
API
ts
function pipe<T extends any[], R>(
...fns: [(...args: T) => any, ...Array<(arg: any) => any>, (arg: any) => R]
): (...args: T) => R | Promise<R>;Parameters
...fns: A sequence of functions to be composed.
Returns
- A new function that represents the pipeline.
Examples
Synchronous Pipeline
ts
import { pipe } from '@vielzeug/toolkit';
const trim = (s: string) => s.trim();
const capitalize = (s: string) => s.toUpperCase();
const exclaim = (s: string) => `${s}!`;
const process = pipe(trim, capitalize, exclaim);
process(' hello '); // 'HELLO!'Asynchronous Pipeline
ts
import { pipe, delay } from '@vielzeug/toolkit';
const fetchUser = async (id: number) => {
await delay(10);
return { id, name: 'Alice' };
};
const getDisplayName = (user: { name: string }) => user.name;
const getUserName = pipe(fetchUser, getDisplayName);
await getUserName(1); // 'Alice'Implementation Notes
- If only one function is provided, it is returned as-is.
- Uses
reduceinternally to chain function calls. - Throws
TypeErrorif any provided argument is not a function.