What is currying in JavaScript
Currying transforms an n-arg function into a chain of unary calls: `f(a, b, c)` becomes `f(a)(b)(c)`. Implemented with closures. Useful for composition, point-free style, and reusable handlers. Distinct from partial application (which pre-fills some args once).
See [[currying-and-partial-application]] for the full treatment. Short version below.
Definition
Currying is converting a function that takes multiple arguments into a sequence of functions that each take one.
function add(a, b, c) { return a + b + c; }
// Curried form: each call returns a function expecting the next arg.
const addC = (a) => (b) => (c) => a + b + c;
addC(1)(2)(3); // 6Generic curry helper
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) return fn(...args);
return (...more) => curried(...args, ...more);
};
}
const sum3 = curry((a, b, c) => a + b + c);
sum3(1, 2, 3); // 6
sum3(1)(2, 3); // 6
sum3(1)(2)(3); // 6fn.length is the declared arity. When enough args are collected, invoke.
Use cases
- Composition —
pipe(prop("user"), prop("name")). - Reusable handlers —
onSelect = (id) => () => dispatch(select(id)). - Point-free style —
map(double)(list)reads top-down. - Configurable helpers —
logger("ERROR")returns a function pre-configured.
Currying vs partial application
- Currying transforms the shape of the function: always unary chain.
- Partial application fixes some args; the rest can still be passed in one call.
bind is partial application:
const addFive = add.bind(null, 5);
addFive(2, 3); // 10Caveats
fn.lengthlies for rest / default params —(a, b = 1) => …has length 1.- Curried functions allocate closures per call — fine for handlers, expensive in hot loops.
- Stack traces get noisier.
When to reach for it
- Functional pipelines (Ramda, lodash/fp).
- Reusable per-item handlers in JSX where you want stable callbacks (when paired with memoization).
- Composing transformations from a vocabulary.
When not to
- Most app code is clearer with normal multi-arg calls.
- Debug-time clarity often beats compositional elegance.
Interview framing
"Currying transforms a multi-arg function into a chain of unary calls — f(a, b, c) becomes f(a)(b)(c). Implemented in ~10 lines with a closure tracking accumulated args until fn.length is reached. Useful for composition pipelines, reusable handlers, and point-free style; overused, it just obscures call sites and makes stack traces noisy. Distinct from partial application — partial pre-fills some args once, currying systematically converts the signature."
Follow-up questions
- •Implement curry from scratch.
- •Difference vs partial application?
- •When does it hurt readability?
Common mistakes
- •Confusing currying and partial.
- •Currying functions with rest/default params (fn.length lies).
Performance considerations
- •Closures per call. Fine for handlers; avoid in tight loops.
Edge cases
- •Default params change fn.length.
- •Curry helpers that allow placeholders (Ramda's `R.__`).
Real-world examples
- •Ramda, lodash/fp, Redux compose, FP-style helpers.