, , ,

Function Currying: Fun & Practical

Posted by

How to break functions into bite-sized calls for flexibility, reuse, and clarity in JavaScript.

How to break functions into bite-sized calls for flexibility, reuse, and clarity in JavaScript.

Introduction

At first glance, function currying feels like one of those “fancy functional programming ideas” that you’ll never actually use in day-to-day development. But once you understand it, you’ll see it everywhere — from event handlers to config builders to React hooks.

Currying isn’t about being clever. It’s about being practical: breaking big, multi-argument functions into smaller, composable ones. That way, you can reuse functions in different contexts, lock in defaults, and write cleaner code.

In this guide, we’ll cover:

  • What currying is (and how it differs from partial application).
  • How to implement it in plain JavaScript.
  • Real-world use cases (React, data transforms, configs).
  • Common pitfalls and how to avoid them.
  • Copy-paste snippets and mental models.

1) What is Currying?

Definition: Currying is the process of transforming a function that takes multiple arguments into a sequence of functions, each taking one argument.

// Regular function
function add(a, b) {
return a + b;
}

// Curried form
function addCurry(a) {
return function(b) {
return a + b;
};
}

add(2, 3); // 5
addCurry(2)(3); // 5

👉 Think of it as: Instead of taking all arguments at once, take them one at a time.


2) Currying vs Partial Application

These terms are often mixed up:

  • Currying: Always breaks a multi-arg function into a chain of single-arg functions.
  • Partial application: Fixes (“pre-fills”) some arguments of a function, leaving the rest.

Example: Partial Application

function multiply(a, b, c) {
return a * b * c;
}

const double = multiply.bind(null, 2); // pre-fill first arg
console.log(double(3, 4)); // 24

Example: Currying

const multiplyCurry = a => b => c => a * b * c;
console.log(multiplyCurry(2)(3)(4)); // 24

👉 All curried functions can be partially applied, but not all partial applications are “curried.”


3) Why Currying is Useful

  • Reusability: Create specialized versions of general functions.
  • Composability: Pipe small functions together.
  • Config-once, use-many: Lock in parameters once (like DB configs, log levels).
  • Cleaner callbacks: No need for inline anonymous functions.
  • Functional style: Encourages predictable, testable code.

4) Implementing Currying in JavaScript

Simple Manual Curry

function curryAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}

console.log(curryAdd(1)(2)(3)); // 6

Generic Curry Utility

function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...next) {
return curried.apply(this, args.concat(next));
};
}
};
}

// Usage
function sum(a, b, c) {
return a + b + c;
}

const curriedSum = curry(sum);
console.log(curriedSum(1)(2)(3)); // 6
console.log(curriedSum(1, 2)(3)); // 6
console.log(curriedSum(1)(2, 3)); // 6

👉 Flexible: accepts arguments in chunks (f(1)(2,3) as well as f(1)(2)(3)).


5) Real-World Examples

Example 1: Event Handlers

const handleEvent = type => element => 
element.addEventListener(type, () => console.log(type, "fired"));

const onClick = handleEvent("click");
onClick(document.querySelector("#btn"));

You “lock in” the event type and reuse across elements.


Example 2: Logging with Context

const log = level => message => console.log(`[${level}] ${message}`);

const info = log("INFO");
const error = log("ERROR");

info("Server started"); // [INFO] Server started
error("Crash detected"); // [ERROR] Crash detected

Example 3: Configuration Factories

const makeRequest = baseUrl => endpoint => params =>
fetch(`${baseUrl}/${endpoint}?${new URLSearchParams(params)}`)
.then(res => res.json());

const api = makeRequest("https://api.example.com");

const getUsers = api("users");
getUsers({ limit: 10 }).then(console.log);

const getPosts = api("posts");
getPosts({ page: 2 }).then(console.log);

Example 4: React & Higher-Order Functions

const withClass = className => Component => props =>
<div className={className}><Component {...props} /></div>;

const RedBox = withClass("red")(props => <span>{props.text}</span>);

Here currying enables clean, reusable HOCs.


Example 5: Filtering/Mapping Pipelines

const greaterThan = x => y => y > x;

const nums = [1, 5, 10, 15];
const gt10 = greaterThan(10);

console.log(nums.filter(gt10)); // [15]

6) Gotchas & Tips

a) Over-Currying Hurts Readability

// ❌ Overkill
const weird = a => b => c => d => e => f => a+b+c+d+e+f;
weird(1)(2)(3)(4)(5)(6);

👉 Don’t curry everything. Curry only when it makes functions more reusable.


b) Arrow Functions Help, but Be Clear

// ✅ Clear
const add = a => b => a + b;

// ❓ Confusing for juniors
const fn = a => b => c => d => e => f => a+b+c+d+e+f;

Use descriptive names and don’t nest endlessly without formatting.


c) Be Aware of this

Curried functions return new closures — methods relying on this can lose context. Always design curried functions as pure functions (based only on arguments).


7) Libraries That Curry for You

  • Lodash / Ramda: Have _.curry and built-in curried functions.
  • Redux / React world: Many hooks and HOCs are designed with currying patterns in mind.
const _ = require("lodash");

const sum = (a, b, c) => a + b + c;
const curried = _.curry(sum);

curried(1)(2)(3); // 6

8) Performance Notes

  • Currying adds extra function calls (each wrapper is a closure).
  • In real apps, overhead is negligible.
  • If perf-critical, avoid deep currying in hot loops.
  • Trade readability vs raw speed consciously.

9) Quick Reference


Conclusion

Currying isn’t about showing off — it’s about making functions more flexible and reusable. By breaking big multi-argument functions into single-purpose, chainable calls, you get:

  • Cleaner event handling.
  • Configurable APIs.
  • Reusable pipelines for data.
  • Simpler testing.

Pro tip: When designing a utility, ask: Will users often reuse this with the same first argument? If yes, curry it. If not, keep it normal.


Call to Action

Have you ever used currying in production — maybe in a React HOC or a logging utility?

💬 Share your snippet in the comments.
🔖 Bookmark this as your currying reference.
👩‍💻 Show it to a teammate who thinks currying is only for FP nerds.

Leave a Reply

Your email address will not be published. Required fields are marked *