before tackling this topic make sure you have a good understanding about closures and higher order functions in general.
Currying is the process of transforming a function that takes multiple arguments into a sequence of functions, each taking one argument at a time. This allows you to create more specialized and reusable functions.
Think of currying like ordering a custom pizza: instead of specifying all your toppings at once, you add them one by one, building up to the final result.
Take a look at this simple example:
// Non-curried function
function multiply(a, b, c) {
return a * b * c;
}
console.log(multiply(2, 3, 4)); // 24
// Curried version
function curriedMultiply(a) {
return function (b) {
return function (c) {
return a * b * c;
};
};
}
console.log(curriedMultiply(2)(3)(4)); // 24
In the curried version, curriedMultiply
takes one argument at a time, returning a new function until all arguments are provided. This might seem like extra work, but it opens up a world of flexibility.
What about the use case?
Currying is like having a toolkit where each tool does one thing really well. It allows you to create partially applied functions—functions that are pre-loaded with some arguments and ready to take the rest later. This is especially useful for reusability and composition.
take a look:
// Curried function to calculate shipping costs
function calculateShippingCost(baseCost) {
return function (weight) {
return function (distance) {
return baseCost + weight * 2 + distance * 0.5;
};
};
}
const standardShipping = calculateShippingCost(10); // Base cost of $10
const heavyItemShipping = standardShipping(20); // Weight of 20kg
console.log(heavyItemShipping(100)); // Shipping cost for 100km: 10 + (20 * 2) + (100 * 0.5) = 80
calculateShippingCost
is a curried function that lets you create specialized shipping calculators. You can reuse standardShipping
and heavyItemShipping
for different scenarios.
Another example to solidify stuff.
// Curried function to create a logger
function createLogger(prefix) {
return function (message) {
return function (timestamp) {
return `[${timestamp}] ${prefix}: ${message}`;
};
};
}
const errorLogger = createLogger("ERROR");
const warnLogger = createLogger("WARN");
console.log(errorLogger("File not found")(new Date().toISOString()));
// [2025-10-15T12:00:00Z] ERROR: File not found
console.log(warnLogger("Low disk space")(new Date().toISOString()));
// [2025-10-15T12:00:00Z] WARN: Low disk space
In this example, createLogger
is a curried function that generates specialized loggers. You can create errorLogger
and warnLogger
with different prefixes, making your logging system more flexible and reusable.
Top comments (3)
Holy molly thanks for your explanation dude. To be honest I’ve never cared about what currying is or when to use it because I’ve never faced a use case as clear as the two you expose here. I’ve seen the light 💡
Glad it clicked for you! 🚀 thanks for reading!
I think use Decorator Pattern may be a less-confusing approach, so we can chain the method calls. Whatever, it's still explained well in your article 👏