Currying: One Argument at a Time, No Exceptions
A stricter cousin of partial application that only ever accepts one argument per call, where the technique gets its name, and the utility that automates it.
Partial application locks in however many arguments you hand it, all at once. Currying takes the same goal, specializing a function step by step, and adds one strict rule: exactly one argument per call, every time.
Writing It by Hand
function apiRequest(endpoint) {
return function (payload) {
return function (callback) {
// the actual request
};
};
}
const getOrder = apiRequest('/orders');
const getCurrentOrder = getOrder({ id: currentOrderId });
getCurrentOrder(renderOrder);Three nested functions, three separate calls, each one peeling off exactly one input before handing back a function waiting for the next. That's currying, written manually.
Where the Name Comes From
This technique is named after Haskell Curry, a mathematician who helped develop the ideas behind it. It's not a coincidence that a language named Haskell only allows unary functions: every function in that language takes exactly one argument, so currying isn't an optional style choice there, it's the only way a function can ever take more than one input.
JavaScript doesn't have that restriction. Currying here is a deliberate choice, not a language requirement.
Automating It
Writing the nested-function version by hand for every multi-argument function gets old fast. A curry utility does it for you:
function curry(fn, arity = fn.length) {
return function curried(...args) {
if (args.length >= arity) return fn(...args);
return (...more) => curried(...args, ...more);
};
}
function apiRequest(endpoint, payload, callback) {
// the actual request
}
const curriedRequest = curry(apiRequest);
const getOrder = curriedRequest('/orders');
const getCurrentOrder = getOrder({ id: currentOrderId });
getCurrentOrder(renderOrder);curry takes an ordinary function and returns one that keeps collecting arguments, one call at a time, until it has enough to actually run the original.
endpoint => payload => callback => { ... }. If you write it that way, wrap each arrow function in its own parentheses. It costs nothing and saves the next reader from re-parsing three nested arrows to find where one function ends and the next begins.Currying and Partial Application Are Cousins, Not the Same Thing
partial(fn, a, b) // both at onceLocks in as many arguments as you hand it, in one call.
curried(a)(b) // one at a timeNever accepts more than one argument per call, no exceptions.
Both exist to turn one general function into a chain of increasingly specific ones. Currying trades away partial application's flexibility for a single, predictable shape: every step takes one thing and returns one function, which is exactly why it composes so cleanly with everything else this series has already covered.
That predictability is also why, in practice, most functional codebases lean on currying far more than partial application, even though both get you to the same destination.
Keep reading