Currying in JavaScript
Currying is considered advanced JavaScript programming, even though it is simple to implement. To put it simple, currying is a function that takes one argument and then returns a function that expects the next one, and so one. The chain of functions can be two or more.
Why should I use currying?
Currying is not needed per se, as with many other concepts and design patterns, but it can be very useful in some scenarios where we want to make our code better in terms of clean code, efficiency and overall maturity of the project.
- Reduce duplications of variables
- Can make a complex function divided into smaller chunks
- Can make the code look cleaner
Examples
Let's dive into some examples, and we will explore how we can make use of the concept of currying.
Calculator
This is a common basic example when one should learn currying, so lets continue that path.
If we consider the non-curried function:
const add = (a, b) => a + b; add(2, 5); // 7
We can create a curried version like this:
const add = (a) => (b) => a + b; add(2)(5); // 7
So what we basically are doing, is to create a function, that return a new function that will execute the logic. Above example is more to show in a simple way of how it is implemented, but perhaps not really a good use case on why you want to use currying. We will explore another case, where it might be more useful.
Logger
Let's do a logger. Our logger will first accept the name of a service, and then our next function will take the severity of the log (verbose, warning or error) and then our last function will accept a message and execute the logic.
const logger = (service) => (severity) => (msg) => { if (severity === "error") { console.error(`Error in ${service}. Error: ${msg}`); } else if (severity === "warning") { console.warn(`Warning in ${service}. Message: ${msg}`); } else if (severity === "verbose") { console.log(`Logging from ${service}: ${msg}`); } else { throw new Error(`Non supported severity ${severity}`); } };
Our logger can now be useful if we implement it in multiple places in a service. For example if we have a JavaScript service called like weatherService.js that are fetching weather data from an API, like our free weather API 😉, we can easily set up our logger in a smooth way instead of always providing a service for example.
So if we imagine we have a service, we can use our logger like this:
weatherService.js
class WeatherService { _errorLogger = logger("weatherService")("error"); getWeather(city) { try { fetch(`https://weather.algobook.info/forecast?city=${city}`); } catch (err) { this._errorLogger(err); } } getCitySuggestions(query) { try { fetch(`https://weather.algobook.info/city/suggestions?query=${query}`); } catch (err) { this._errorLogger(err); } } }
In above example, we are only interested in errors for example, and then we can set up our logger one time with the service and severity and then only pass the error message instead of always providing the service name and severity.
Conclusion
In this article, we touched upon the concept of currying in JavaScript. We showed some basic examples of how we can use it, and also why it can be beneficial to use it. Currying is quite uncommon I would say, in my years as a developer I have rarely seen it in projects, but personally I like the concept and I see the benefits of using it to make the code more efficient and more convenient to work with.
I hope this article shed some light in what currying is, and how to implement it. To learn more, simply add it to your project and build your knowledge from there and try to find places where it make sense to convert your functions into curried versions.
Thanks for reading, and don't hesitate to contact us if you have any questions or feedback.