Back to JavaScript
JavaScript
easy
mid

How would you write a curried multiplication function where mul(2)(3)(4) equals 24?

Currying via closures: each call returns a function that captures the running product. The trick is the function must also coerce to its value — implement valueOf/toString so mul(2)(3)(4) evaluates to 24 when used as a number.

4 min read·~12 min to think through

mul(2)(3)(4) === 24 is a currying + closure problem with a twist: the result of each call is a function (so it can be called again), but it must also be usable as the number.

The naive version (fixed arity)

If it's always exactly three calls:

js
const mul = (a) => (b) => (c) => a * b * c;
mul(2)(3)(4); // 24

Clean, but mul(2)(3) would be a function, not 6 — and it only handles 3 args.

The real ask: infinite chaining — mul(2)(3)(4)...

Each call returns a function carrying the running product. The key trick: that function needs to coerce to its numeric value when compared or used as a number, via valueOf (or toString):

js
function mul(a) {
  function next(b) {
    return mul(a * b);          // return another chainable function
  }
  next.valueOf = () => a;       // coercion: makes it usable as the number
  next.toString = () => String(a);
  return next;
}

mul(2)(3)(4) == 24;   // true  — == triggers valueOf
+mul(2)(3)(4);        // 24    — unary + triggers valueOf
  • Every mul(x) returns next, which is callable (chain continues) and has a valueOf so JS coerces it to the accumulated product in numeric contexts.
  • Note: === won't coerce — mul(2)(3)(4) === 24 is false because it's strictly a function. Use ==, +x, or template/string context. Interviewers usually accept == / explain this nuance.

What this tests

  • Closures — the running product captured across calls.
  • Currying / function returning function.
  • Type coercionvalueOf/toString and when JS invokes them. Knowing === won't coerce is the senior detail.

Variation: sum that works with any number of calls

Same pattern: add(1)(2)(3) with valueOf accumulating. The technique generalizes to any "chainable accumulator."

Follow-up questions

  • Why does the chained function need valueOf/toString?
  • Why does === fail but == works?
  • How would you write a fixed-arity curry instead?
  • How would you generalize this to add(1)(2)(3)...?

Common mistakes

  • Returning the product directly, so the result isn't chainable.
  • Forgetting valueOf/toString, so it can't be used as a number.
  • Expecting === to work (it doesn't coerce).
  • Hardcoding three levels instead of supporting arbitrary chaining.

Performance considerations

  • Each call allocates a closure; fine for interview-scale chains. Not a real-world pattern — it's a JS-mechanics exercise.

Edge cases

  • mul(2) used alone — should coerce to 2.
  • Strict equality (===) won't coerce — explain the limitation.
  • Zero in the chain → product is 0.

Real-world examples

  • Demonstrates the closure/coercion mechanics behind currying utilities (lodash.curry) and chainable builder APIs.

Senior engineer discussion

Seniors immediately separate the two requirements — the result must be re-callable AND coerce to a number — and reach for valueOf/toString. The senior detail is explaining that === can't work because it doesn't coerce, and generalizing the pattern to any chainable accumulator.

Related questions