
kiran raviIf you've spent time in the functional programming world or looked at the source code of libraries...
If you've spent time in the functional programming world or looked at the source code of libraries like Redux, you’ve likely encountered functions that look like this: const result = add(5)(10)(20);.
At first glance, it looks like a typo. But it’s actually one of the most powerful patterns in JavaScript: Function Currying.
Currying is a functional programming technique where a function that takes multiple arguments is transformed into a sequence of nesting functions, each taking a single argument.
Instead of: f(a, b, c)
You get: f(a)(b)(c)
Currying doesn’t actually call a function; it transforms it. The execution only happens once the last argument in the chain is provided.
Currying is only possible in JavaScript because of Closures. When the outer function is called, it returns the inner function. Even after the outer function has finished executing, the inner function "remembers" the variables in the outer scope.
The Standard Way:
const multiply = (a, b) => a * b;
console.log(multiply(2, 5)); // 10
The Curried Way:
const curriedMultiply = (a) => {
return (b) => {
return a * b;
};
};
const double = curriedMultiply(2); // 'a' is locked as 2
console.log(double(5)); // 10
The most practical way to think about Currying is as Function Configuration. You provide the "setup" arguments first and the "data" arguments later.
Imagine you are building a dashboard that fetches data from different services but uses the same API Key.
const apiCall = (apiKey) => (resource) => (id) => {
return `Fetching ${resource} #${id} using key: ${apiKey}`;
};
// Step 1: Initialize with the API Key (Configuration)
const privateRequest = apiCall("SECRET_TOKEN_99");
// Step 2: Configure for specific resources
const getProduct = privateRequest("products");
const getUser = privateRequest("users");
// Step 3: Use in real-time
console.log(getProduct("A101")); // Fetching products #A101 using key: SECRET_TOKEN_99
console.log(getUser("007")); // Fetching users #007 using key: SECRET_TOKEN_99
In React, currying is frequently used to handle list items without creating an anonymous arrow function inside the render method, which can help with performance and readability.
const Shop = () => {
// Curried handler
const addToCart = (productId) => (event) => {
console.log(`Item ${productId} added by clicking ${event.target.id}`);
};
const products = [{id: 'p1', name: 'Laptop'}, {id: 'p2', name: 'Mouse'}];
return (
<div>
{products.map(p => (
<button key={p.id} id="btn-add" onClick={addToCart(p.id)}>
Add {p.name}
</li>
))}
</div>
);
};
Note: addToCart(p.id) is executed during render, returning the actual function that onClick will use.
These terms are often used interchangeably, but there is a technical distinction:
f(a, b, c) -> f(a)(b)(c)
Partial Application: Fixes a subset of arguments and returns a function for the rest.
f(a, b, c) -> f(a)(b, c) (Note: the second function takes two arguments).
[Image comparing Function Currying versus Partial Application showing the number of arguments handled at each step]
curry() Helper
In a professional environment, you won't always write functions in curried form. You can use a "Curry Utility" to transform existing functions.
function curry(fn) {
return function curried(...args) {
// If the number of arguments provided matches the original function...
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
// ...otherwise, return a new function to collect the rest
return function(...nextArgs) {
return curried.apply(this, args.concat(nextArgs));
}
}
};
}
// Transform a standard function
const sum = (a, b, c) => a + b + c;
const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // 6
console.log(curriedSum(1, 2)(3)); // 6 (Hybrid approach)
logError("Database failed") is much more readable than log("Error", "Server", "Database failed").