Back to JavaScript
JavaScript
easy
mid

What is currying in JavaScript and when would you use it?

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).

3 min read·~8 min to think through

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.

js
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);  // 6

Generic curry helper

js
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);     // 6

fn.length is the declared arity. When enough args are collected, invoke.

Use cases

  • Compositionpipe(prop("user"), prop("name")).
  • Reusable handlersonSelect = (id) => () => dispatch(select(id)).
  • Point-free stylemap(double)(list) reads top-down.
  • Configurable helperslogger("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:

js
const addFive = add.bind(null, 5);
addFive(2, 3);    // 10

Caveats

  • fn.length lies 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.

Senior engineer discussion

Seniors know when currying helps composition and when it just obscures call sites — they don't over-apply it.

Related questions