🧠 Mastering Functional Programming in JavaScript: Compose, Pipe, and Currying

pushpesh kumarpushpesh kumar
3 min read

Functional Programming (FP) can feel overwhelming at first—but once you get the hang of it, you’ll write cleaner, more reusable, and testable JavaScript code.

In this article, we’ll break down three core FP concepts:

  • compose

  • pipe

  • currying

Let’s understand each with simple code examples and analogies.


🔁 compose: Right-to-Left Function Chaining

🧾 What is compose?

compose is a utility that chains functions together. It runs functions from right to left, passing the output of one function into the next.

🧠 Analogy

Imagine you’re getting ready:

  1. Wear shoes

  2. Put on socks

  3. Take a shower

Now, to actually get ready, you'd:

  • Shower ➝ then Socks ➝ then Shoes

That’s right to left — like compose.

🧪 Example

const toUpper = (str) => str.toUpperCase();
const exclaim = (str) => `${str}!`;
const greet = (name) => `Hello, ${name}`;

const compose = (...fns) => (value) =>
  fns.reduceRight((acc, fn) => fn(acc), value);

const welcome = compose(exclaim, toUpper, greet);

console.log(welcome("pushpesh")); // ➝ HELLO, PUSHPESH!

🔄 pipe: Left-to-Right Function Chaining

🔄 What is pipe?

Just like compose, but left to right. This feels more natural when reading code.

📖 Analogy

Back to our morning routine:

  1. Shower

  2. Socks

  3. Shoes

That’s the exact order you follow — and that’s pipe.

🧪 Example

const pipe = (...fns) => (value) =>
  fns.reduce((acc, fn) => fn(acc), value);

const welcomePipe = pipe(greet, toUpper, exclaim);

console.log(welcomePipe("pushpesh")); // ➝ HELLO, PUSHPESH!

🧩 Currying: One Argument at a Time

🔍 What is Currying?

Currying turns a function that takes multiple arguments into a chain of functions, each taking one argument.

🧠 Analogy

Ordering coffee:

  • Step 1: Choose coffee type (latte)

  • Step 2: Choose size (medium)

  • Step 3: Choose milk (oat)

You can customize each step along the way.

🧪 Example

// Normal
function add(a, b) {
  return a + b;
}

// Curried
function curriedAdd(a) {
  return function (b) {
    return a + b;
  };
}

console.log(curriedAdd(2)(3)); // ➝ 5

🔁 Reusability with Currying

const add2 = curriedAdd(2);
console.log(add2(10)); // ➝ 12
console.log(add2(100)); // ➝ 102

🎯 Why Should You Care?

  • 🧼 Clean, declarative code

  • 🔁 Easy function reuse

  • 🧪 Better testability

  • 🔄 Encourages immutability


🧰 Bonus: Build Your Own compose, pipe, curry

// Compose (Right to Left)
const compose = (...fns) => (value) =>
  fns.reduceRight((acc, fn) => fn(acc), value);

// Pipe (Left to Right)
const pipe = (...fns) => (value) =>
  fns.reduce((acc, fn) => fn(acc), value);

// Curry (2-arg)
const curry = (fn) => (a) => (b) => fn(a, b);

🏁 Final Thoughts

You don’t need to master all of functional programming to benefit from it. Start small:

  • Use pipe to make transformations more readable.

  • Use compose when chaining logic in reverse makes more sense.

  • Use currying to create flexible, reusable functions.

Once these become second nature, you'll feel like you're playing with Lego blocks—snapping together small, powerful pieces to build great apps.


💬 Over to You

Have you used compose or currying in a real project? Or found it confusing? Let me know in the comments — let’s learn together.

0
Subscribe to my newsletter

Read articles from pushpesh kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

pushpesh kumar
pushpesh kumar