Skip to the code
cf.

Pipe

Write pipe(...fns). It returns one function that runs fns from left to right, feeding each result into the next: pipe(f, g, h)(x) is h(g(f(x))).

The first function gets all the arguments and the caller's this; every later function gets the previous result as its only argument.

With no functions, pipe() returns a function that returns its first argument. If any argument isn't a function, pipe throws a TypeError right away, before anything is called. The piped function can be called any number of times.

const slugify = pipe(
  (s) => s.trim(),
  (s) => s.toLowerCase(),
  (s) => s.replaceAll(" ", "-"),
);
slugify("  Hello World "); // "hello-world"
 
const doubleSum = pipe((a, b) => a + b, (n) => n * 2);
doubleSum(10, 15); // 50

What the tests check

  1. runs the functions from left to right
    expect(pipe((x) => x + 1, (x) => x * 2)(3)).toBe(8);
    expect(pipe((s) => s + "a", (s) => s + "b", (s) => s + "c")("")).toBe("abc");
    
  2. the first function gets all the arguments
    expect(pipe((a, b) => a + b, (x) => x * 10)(2, 3)).toBe(50);
    
  3. the later functions get only the previous result
    const last = spy((x) => x);
    pipe((a, b) => a * b, last)(4, 5);
    expect(last.calls[0].args).toEqual([20]);
    
  4. passes the caller's this to the first function
    const obj = {
      n: 4,
      next: pipe(
        function () {
          return this.n;
        },
        (x) => x + 1,
      ),
    };
    expect(obj.next()).toBe(5);
    
  5. with no functions, returns the first argument
    const value = { id: 1 };
    expect(pipe()(value)).toBe(value);
    expect(pipe()(5, 6)).toBe(5);
    
  6. gives the same answer every time it's called
    const addAB = pipe((s) => s + "a", (s) => s + "b");
    expect(addAB("")).toBe("ab");
    expect(addAB("")).toBe("ab");
    expect(addAB("x")).toBe("xab");
    
  7. throws a TypeError right away if an argument isn't a function
    expect(() => pipe((x) => x, null)).toThrow(TypeError);
    expect(() => pipe({})).toThrow(TypeError);
    

Learn more

solution.jsSaved in this browser

Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.

Ctrl + Enter runs the tests (⌘ + Enter on a Mac).