DEV Community

Cover image for Currying in JavaScript
Pratik Soni
Pratik Soni

Posted on

Currying in JavaScript

When I first learned JavaScript, concepts like currying felt confusing and unnecessary—until I actually started using it.

Think about ordering coffee. You don't shout everything at once.
You decide step by step — first, you choose the type of coffee, then the size, and finally the milk.

The same idea applies to currying in JavaScript.
Currying allows us to call a function like this:

orderCoffee('Latte')('Medium')('Almond milk');

Each function call captures one piece of information and returns control to another function, which waits for the next input.

Let’s look at a simple example:

function orderCoffee(type) {
  return function (size) {
    return function (milk) {
      return `You selected ${type} ${size} with ${milk}`;
    };
  };
}

const orderOne = orderCoffee('Latte')('Medium')('Almond milk');
const orderTwo = orderCoffee("Americano")('Large')('No milk');
const orderThree = orderCoffee('Mocha')('Medium')('Almond milk');
Enter fullscreen mode Exit fullscreen mode

Currying breaks a function into smaller functions, each taking one argument, and allows you to reuse behavior instead of repeating code.

Let’s break down what happens internally.

Step 1: const step1 = orderCoffee('Latte')

  • type = 'Latte'
  • Returns a function
  • That function remembers the type via closure

Now the function looks like this internally

function (size) {
  return function (milk) {
   return `You selected Latte ${size} with ${milk}`;
  };
};
Enter fullscreen mode Exit fullscreen mode

Step 2: const step2 = step1('Medium')

  • size = 'Medium'
  • Returns another function
  • Remembers size and type via closure

Now the function becomes

function (milk) {
  return `You selected Latte Medium with ${milk}`;
};
Enter fullscreen mode Exit fullscreen mode

Step 3: const finalStep = step2('Almond milk')

Once all arguments are provided, the function returns the final result:

const orderOne = orderCoffee('Latte')('Medium')('Almond milk');

Output:
You selected Latte Medium with Almond milk
Enter fullscreen mode Exit fullscreen mode

Now let's see currying in an arrow function

const orderCoffee = (type) => (size) => (milk) =>
  `You selected ${type} ${size} with ${milk}`;

const order = orderCoffee('Latte')('Medium')('Almond milk');
Enter fullscreen mode Exit fullscreen mode

Arrow functions make currying look cleaner, but the internal working remains the same — let’s break it down.

Execution Flow

Step 1: order = orderCoffee('Latte')

  • Returns a function waiting for size. Now the string becomes: You selected Latte ${size} with ${milk}

Step 2: order = orderCoffee('Latte')('Medium')

  • Returns a function waiting for milk. Now the string becomes: You selected Latte Medium with ${milk}.

Step 3: order = orderCoffee('Latte')('Medium')('Almond milk')
All arguments are provided, and the final string is returned:

order = orderCoffee('Latte')('Medium')('Almond milk')

Output
You selected Latte Medium with Almond milk. 
Enter fullscreen mode Exit fullscreen mode

Summary

Currying is a functional programming technique that transforms a function with multiple parameters into a sequence of functions like (f(a,b,c) ~~~~> f(a)(b)(c)), each accepting a single argument. Currying relies heavily on closures. Each nested function retains access to the arguments provided in previous calls, allowing values to be accumulated until all required parameters are available. Once the expected number of arguments is collected, the original function executes and returns the final result.

That’s it for this article — see you in the next blog!

Top comments (0)