Suggest an editImprove this articleRefine the answer for “Implementing compose”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`compose()`** is a combinator function that merges several functions into one: `compose(f, g, h)(x)` is equivalent to `f(g(h(x)))` (it executes right to left). **Key point:** its counterpart `pipe()` executes functions left to right.Shown above the full answer for quick recall.Answer (EN)Image`compose()` is a combinator function that merges several functions into one: `compose(f, g, h)(x)` is equivalent to `f(g(h(x)))` (it executes **right to left**). --- ## Minimal implementation (ES6) ```javascript // Universal version: the last handler can accept many arguments const compose = (...fns) => (...args) => fns.reduceRight( (acc, fn) => [fn(...acc)], args )[0]; // Example const trim = s => s.trim(); const toInt = s => parseInt(s, 10); const inc = n => n + 1; const parseAndInc = compose(inc, toInt, trim); parseAndInc(' 41 '); // 42 ``` --- ## A variant for **unary** functions (a bit faster and simpler) ```javascript const composeUnary = (...fns) => x => fns.reduceRight((v, fn) => fn(v), x); ``` --- ## Promise-aware (asynchronous compose) Works with both sync and async functions. ```javascript const composeAsync = (...fns) => (...args) => fns .slice(0, -1) .reduceRight( (p, fn) => p.then(res => fn(res)), Promise.resolve(fns[fns.length - 1](...args)) ); // Example const fetchUser = async id => ({ id, name: 'Tim' }); const getName = u => u.name; const shout = s => s.toUpperCase(); const getUserNameLoud = composeAsync(shout, getName, fetchUser); getUserNameLoud(7).then(console.log); // 'TIM' ``` --- ## A type-safe version for TypeScript (practical overloads) (Covers up to 4 functions; can be extended the same way.) ```javascript type Unary<A, R> = (a: A) => R; export function compose<A, R>(f1: Unary<A, R>): Unary<A, R>; export function compose<A, B, R>( f1: Unary<B, R>, f2: Unary<A, B> ): Unary<A, R>; export function compose<A, B, C, R>( f1: Unary<C, R>, f2: Unary<B, C>, f3: Unary<A, B> ): Unary<A, R>; export function compose<A, B, C, D, R>( f1: Unary<D, R>, f2: Unary<C, D>, f3: Unary<B, C>, f4: Unary<A, B> ): Unary<A, R>; export function compose(...fns: Function[]) { return (x: unknown) => fns.reduceRight((v, f) => f(v), x); } ``` --- ## You often also need `pipe()` (left to right) ```javascript const pipe = (...fns) => (...args) => fns.reduce((acc, fn) => [fn(...acc)], args)[0]; const parseAndInc2 = pipe(trim, toInt, inc); parseAndInc2(' 41 '); // 42 ``` --- ### Useful notes - If you're composing **object methods**, don't forget about `this`: bind them with `fn.bind(obj)`. - Try to keep functions **pure** and **unary** - composition will be simpler and more predictable. - For production it's convenient to have both variants: `compose` (R→L) and `pipe` (L→R), plus `composeAsync/pipeAsync`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.