DEV Community

Cover image for Writing a curried add in JavaScript
Lydia Yuan
Lydia Yuan

Posted on

Writing a curried add in JavaScript

I wanted to create a curried add function that allows for unlimited chaining, like add(1)(2)...(n). I started with a curry function that returns a curried version of the input function:

const curry = (fn) => {
  const curried = (...args) => {
    if (args.length >= fn.length) {
      return fn(...args);
    }
    return (...moreArgs) => curried(...args, ...moreArgs);
  };
  return curried;
}
Enter fullscreen mode Exit fullscreen mode

Next, I tried to use curry to create a curriedAdd function with fixed parameters:

const add = (a , b) => a + b

const curriedAdd = curry(add)

console.log(curriedAdd(2, 3))
// 5

console.log(curriedAdd(2)(3))
// 5

console.log(curriedAdd(2)(3)(4))
// Oops an error!
// Uncaught TypeError: curriedAdd(...)(...) is not a function at <anonymous>:5:29
Enter fullscreen mode Exit fullscreen mode

However, I encountered a problem while trying to achieve unlimited chaining using the currying technique. JavaScript functions have a fixed number of parameters, which makes it impossible to create a function that can accept an unlimited number of arguments without using some sort of workaround.

When we call curriedAdd(2), it returns a function that takes another parameter and adds it to 2. Therefore, curriedAdd(2)(3) results in a number 5.

But attempting to call 5(4) leads to a runtime error since 5 is a number and not a function that can accept another argument.

Instead, I came up with a solution that involves returning a function that can be called with an empty argument to indicate the end of the chain. With this approach, the user needs to manually call the function with an empty argument () to signal the end of the chain.

Although this requires a bit more effort from the user to call the execution, it allows for an unlimited number of arguments to be passed in a curried manner, as demonstrated by add(1)(2)...(n)().


const add = (x) => {
  let sum = x;

  const innerAdd = (y) => {
    if (y !== undefined) {
      sum += y;
      return innerAdd;
    } else {
      return sum;
    }
  };

  return innerAdd;
};



add(1)(2)(3)(); // returns 6
add(1)(2)(3)(4)(5)(); // returns 15
Enter fullscreen mode Exit fullscreen mode

Alternatively, if we know the expected number of parameters ahead of time, we can use curry with a fixed number of arguments:


const curryN = (fn, fnArgsLen = fn.length) =>
  (...args) =>
    args.length >= fnArgsLen
      ? fn(...args)
      : (...moreArgs) => curryN(fn, fnArgsLen)(...args, ...moreArgs);


const add = (x, y, z) => x + y + z
const curriedAdd = curryN(add, 3);

console.log(curriedAdd(1)(2)(3)); // prints 6
console.log(curriedAdd(1, 2)(3)); // prints 6
console.log(curriedAdd(1, 2, 3)); // prints 6
Enter fullscreen mode Exit fullscreen mode

While this approach isn't truly unlimited chaining, it can handle a large number of arguments and provides a flexible way to compose functions.

Top comments (0)