pipe(f, g, h)(x) applies functions left-to-right: h(g(f(x))). The TypeScript challenge is making the types flow through the chain:
const process = pipe(
(x: string) => x.trim(), // string → string
(x: string) => x.split(','), // string → string[]
(x: string[]) => x.length, // string[] → number
);
process(' a, b, c '); // → 3
// TypeScript infers return type: number ✅
// TypeScript enforces each function receives the correct input type ✅Without overloads, pipe would return unknown. With overloads, TypeScript picks the right type per arity:
function pipe<A, B>(f: (a: A) => B): (a: A) => B;
function pipe<A, B, C>(f1: (a: A) => B, f2: (b: B) => C): (a: A) => C;
// ...pipe(...fns) — returns a single function that applies fns left-to-right using Array.prototype.reduce.
Available transform functions for testing: double, addOne, negate, toString, toNumber, trim, upper, lower.
Sample tests