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