JavaScript
Function Currying

Function Currying

Function currying is a technique of transforming a function that takes multiple arguments into a sequence of functions that take one or more arguments.

Defining

example.js
const normalFunction = (arg1, arg2) => {
  return [arg1, arg2];
};
 
const curryingFunction = (arg1) => (arg2) => {
  return [arg1, arg2];
};

Calling

example.js
normalFunction("foo", "bar"); //returns ["foo", "bar"]
 
curryingFunction("foo")("bar"); //returns ["foo", "bar"]

Usage

Imagine a function that takes another function as an argument:

example.js
const functionWithCallback = (callback) => {
  const internalValue = "internal";
  return callback(internalValue);
};

In such a case, to pass a callback function that will use internalValue as one of the arguments, we have to use the following construction:

example.js
functionWithCallback((internal) => normalFunction("external", internal));
// returns ['external', 'internal']

If we use our curryingFunction instead, we don't have to create a new arrow function: instead, we pass the call of the whole function, which will be returned by the callback:

example.js
functionWithCallback(curryingFunction("external"));
// returns ['external', 'internal']

Example #1

A typical example of using such a construction is passing a function to the onChange prop in react components:

myComponent.js
import { useState } from "react";
import { Input } from "#components/Input/Input";
 
export const MyComponent = () => {
  const [normalState, setNormalState] = useState("");
  const [curryingState, setCurryingState] = useState("");
  const [lastUsedField, setLastUsedField] = useState("none");
 
  const onChangeHandler = (event, field) => {
    setNormalState(event.target.value);
    setLastUsedField(field);
  };
 
  const curryingOnChangeHandler = (field) => (event) => {
    setCurryingState(event.target.value);
    setLastUsedField(field);
  };
 
  return (
    <div>
      <Input
        value={normalState}
        onChange={(event) => onChangeHandler(event, "normal")}
        label="normal"
      />
      <Input
        value={curryingState}
        onChange={curryingOnChangeHandler("currying")}
        label="currying"
      />
      <p>Last field changed: {lastUsedField}</p>
    </div>
  );
};

Demo

normal:
currying:

Last field changed: none

Example #2

Another example may be passing a function to objects that have their own methods:

myObj.js
const myObj = {
  internalContext: "context",
  test: function (callback) {
    callback(this.internalContext);
  },
};
 
testWithInternalContext = (valueToTest) => (context) => {
  console.log(valueToTest, context);
};
 
//both returns "foo context"
myObj.test(testWithInternalContext("foo"));
myObj.test((context) => testWithInternalContext("foo")(context));