
Currying in JavaScript Explained

Currying is a functional programming technique which transforms a function with multiple arguments into a series of functions, each accepting a single argument. This is a technique that originates from lambda calculus and is widely used in functional languages like Haskell and Lisp. In JavaScript, currying allows for better composition and reusability, aligning with its functional programming roots. Whilst JavaScript is not a purely functional language, it supports functional programming principles, making currying a valuable technique.
In this article, I will explore how currying works in JavaScript, its benefits, and how it compares to partial applications. Hopefully, you will understand how to implement currying and when to use it effectively.
What is Currying?
Starting at the very beginning, what even is currying? Essentially (and I apologise, you've already read this above), currying converts a function that accepts multiple arguments into a sequence of single‑argument functions. Instead of calling a function with all the arguments at once, you can pass them to each function, one at a time.
It's much easier to understand with an example (or two), so...
An Example Without Currying
Here, we have a classic number‑adding function, which accepts two arguments at once, and returns the sum of them both:
const add = (a: number, b: number): number => a + b;console.log(add(2, 3)); // Output: 5This is a very generic and standard way of defining functions in JavaScript, where all parameters are passed together.
An Example with Currying
With currying, on the other hand, the same functionality is transformed so that the function accepts arguments one at a time:
const curriedAdd = (a: number) => (b: number) => a + b;console.log(curriedAdd(2)(3)); // Output: 5When curriedAdd(2) is called, it returns a new function which then accepts a single argument, b. At this stage, the function isn't executed yet; it is just waiting for b to be provided. When we call curriedAdd(2)(3), the inner function receives 3 and finally computes 2 + 3, returning 5.
This structure is useful because it allows partial application, which means that we can call curriedAdd(2) once and then reuse the returned function multiple times with different values for b.
For example:
const addTwo = curriedAdd(2);console.log(addTwo(3)); // Output: 5console.log(addTwo(10)); // Output: 12Here, curriedAdd(2) returns a new function that always adds 2 to whatever value its input is, making it reusable for adding different values of b.
This is an incredibly simplistic example, but, hopefully, it will help set the groundwork for more complicated examples to follow...
Benefits of Currying
1. Function Reusability
Currying allows us to create specialized versions of functions easily. For example:
const multiply = (a: number) => (b: number) => a * b;const double = multiply(2);console.log(double(5)); // Output: 102. Avoiding Repetitive Code
It helps avoid repeating function calls with common arguments.
const greet = (greeting: string) => (name: string) => `${greeting}, ${name}!`;const sayHello = greet("Hello");console.log(sayHello("Ellie")); // Output: Hello, Ellie!3. Function Composition
Currying makes it easier to compose functions by chaining operations rather than repeatedly calling the same function, with (some of) the same values each time.
Implementing a Generic Curry Function
To apply currying dynamically to the code we're writing, we can write a helper function that might look like this:
const curry = (fn: Function) => { return function curried(...args: any[]) { return args.length >= fn.length ? fn.apply(null, args) : (...nextArgs: any[]) => curried(...args, ...nextArgs); };};const sum = (a: number, b: number, c: number) => a + b + c;const curriedSum = curry(sum);console.log(curriedSum(1)(2)(3)); // Output: 6What this does, is check to see if the expected number of arguments has been provided. If not, it returns a new function awaiting the remaining arguments.
A Real‑World Example of Currying
So far in this article, we've focused on currying with numbers because it's a fairly straightforward way to demonstrate what's going on. However, currying is particularly useful in real‑world applications, too, like handling API requests or event listeners. To offer a more real‑world example, consider a scenario where we need to log user actions with different levels of severity. Using currying, we can achieve this like this:
const logMessage = (level: string) => (component: string) => (message: string) => console.log(`[${level}] (${component}): ${message}`);const errorLogger = logMessage("ERROR");const authLogger = errorLogger("AuthModule");authLogger("Invalid password attempt");// Output: [ERROR] (AuthModule): Invalid password attemptauthLogger("User not found");// Output: [ERROR] (AuthModule): User not foundHere, logMessage is curried so that we can create specialised loggers. The first function fixes the severity level, the second fixes the component, and the final function logs the message. This structure allows flexible and reusable logging without repeatedly passing the same arguments to the logger.
Coincidentally, this is actually a pattern I often use when logging API calls and behaviours in my Next.js projects.
Currying vs. Partial Application
Currying
- Always breaks down a function into unary functions (one argument at a time).
- Requires all arguments, eventually.
Partial Application
- Fixes some arguments whilst keeping the function callable with fewer parameters.
const partial = (fn: Function, ...presetArgs: any[]) => (...laterArgs: any[]) => fn(...presetArgs, ...laterArgs);const multiply = (a: number, b: number, c: number) => a * b * c;const multiplyByTwo = partial(multiply, 2);console.log(multiplyByTwo(3, 4)); // Output: 24Here, partial allows setting initial arguments while still leaving others open for later use.
When to Use Currying
Enhancing reusability
: Ideal for setting predefined arguments in frequently used functions.Functional programming
: Works well with composition techniques.Improving readability
: Can make complex functions more manageable and declarative.
Wrapping up
To summarise all of the above, currying is a powerful concept that transforms multi‑argument functions into a sequence of unary functions. It enables reusability, function composition, and cleaner code.
Key Takeaways
- Currying converts a function into a series of functions, each taking a single argument.
- It improves function reusability and composability.
- It differs from partial application, which fixes some arguments but keeps the function callable with the rest.
- A
curryhelper function can make any function curried dynamically.
Understanding and using currying effectively can help write cleaner, more reusable JavaScript code in functional programming contexts.
Categories:
Related Articles

LeetCode: Removing the nth Node from the End of a List. LeetCode: Removing the

Understanding the Difference Between <b> and <strong>. Understanding the Difference Between
<b>and<strong>
Using CommonJS to Implement Modules in JavaScript. Using CommonJS to Implement Modules in JavaScript

3Sum in JavaScript: Two Pointers After Sorting. 3Sum in JavaScript: Two Pointers After Sorting

How to Use and Clear the CSS float Property. How to Use and Clear the CSS
floatProperty
LeetCode: Converting Integers to Roman Numerals. LeetCode: Converting Integers to Roman Numerals

Dynamic Routes in Next.js. Dynamic Routes in Next.js

Mastering CSS Animations with @keyframes. Mastering CSS Animations with
@keyframes
CSS visibility: Hiding Elements Without Affecting Layout. CSS
visibility: Hiding Elements Without Affecting Layout
Check If Your Site is Running on localhost. Check If Your Site is Running on
localhost
The will‑change Property in CSS. The
will‑changeProperty in CSS
Spread Syntax in JavaScript (...). Spread Syntax in JavaScript (
...)