What Is Currying in JavaScript and Why Does It Matter?

0 Comments

Currying is a topic that often sits in the more advanced user circles of JavaScript. It extends beyond the usual usage of functions and methods and starts to dive into the structural side of code.

When you start to build more complex applications, you start looking into your toolbox for architecture and structural knowledge kit sets to help keep your team’s code sanity intact and ensure a certain level of clean code. Currying is one of these methodologies.

So what is currying? How does it work? Why does it matter? And how do you apply it in your functions?

But before we get into all that, we need to first talk about functional programming.

A Quick Primer on Functional Programming

By design, JavaScript is multi-paradigm. This means that it doesn’t conform to just one single pattern of coding. You can mix and match from a range of patterns, and functional patterns are one of them.

When we start learning about code, we’re often told that everything is an object. But the truth is not everything is an object. There are certain things that just simply don’t fit into the object-oriented way of thinking.

Functional programming is a style of writing code that involves a pattern of passing functions as arguments and the ability to return functions without causing side effects.

Immutability is one of functional programming’s best features.

The ability to pass and return functions is done through one of three concepts: pure functions, higher-order functions, and currying.

What Is Currying?

No, we’re not talking about the Indian spice. Rather, we’re talking about the process where a function takes multiple arguments one at a time.

So rather than having a function that looks like this:

fakeFunction('param1', 'param2', 'param3');

You end up with something like this:

fakeFunction('param1')('param2')('param3');

What happens here is that when you pass in a parameter, the first function processes it, then returns a function that processes the next parameter. This lets you chain your arguments in a way that prevents it from having any side effects.

How?

When you apply functional programming ideas to your code, your function does one thing and one thing only: It results in an output that can’t be disputed. The shape of your data doesn’t change. Mutability caused by side effects is reduced to zilch.

When you have more than one argument, you’re setting yourself up for potential side effects. However, when you curry your code, your first argument returns an expected outcome that proceeds to process your next argument, and so on and so forth.

A curried function can look something like this:

function fakeFunction(param1){ 
   //do something 
   return (param2) => { 
     //do something   
     return (param3) => { 
        return finalResult;    
     }  
   }
}

The final function in the chain has access to all the arguments in the chain.

The fun part with curried functions is that you still have access to the functions inside the curried function.

How?

Like this:

let someParam = fakeFunction(param1);
let anotherParam = someParam(param2);
//and then when you call it...
console.log(anotherParam(param3));

This means that regardless of how it’s called, as long as the sequence is correct, the final result will always return as expected.

And that’s the basic structure of currying, but…

How and Where Would You Use Currying in Your JavaScript Code?

Let’s say you have a bunch of functions that need to perform in a particular order. You could, in theory, place all the code in one function, but that would just end up causing chaos in the long run.

What you want are nice, light, and clean-looking functions that aren’t so longwinded that they give your IDE and brain a mini-meltdown.

Currying lets you do this.

It lets you compose the sequence of your functions and ensures that the particular sequence is enforced and followed. The final output is only returned when all the dependencies have been passed through.

Let’s say you want to achieve the following process:

check if stock exists 
   --> check warehouse
      --> deduct stock amount

Your curried function may look something like this:

function checkStock(stockID){ 
   //some check code 
   if(err){throw err;} 
 
   return (warehouseID) => { 
      //some check code 
      if(err){throw err;}
      return(stockDeduct)=> { 
        //some check code         
        if(err){throw err;}
         return stockID 
                + ' from ' + warehouseID
                + ' is reduced by ' + stockDeduct;      
      }
   }
}

And your invocation can look something like this:

let orderItem298 = checkStock('FN9382')('SOUTH')(3);

Yes, you could merge all three functions into one, but then how do you effectively detect issues every step of the way? Currying lets you do it in an elegant manner.

But what if you’ve got more than two or three steps? Wouldn’t the nest be so deep that it starts to look like the pyramid of doom in disguise?

This is the visual downfall of currying.

That’s why, as awesome as currying is, you have to be selective about where you apply it.

The point of currying is that if you don’t provide all the parameters for a function, it returns a function that tells you what’s left in the list. In a way, it is a checking method to make sure that you’ve got everything you need before you proceed.

It can be used as a precursor before your actual function. For example:

function prepInvoiceLine(stockID){ 
   //some check code 
   if(err){throw err;} 
 
   return (warehouseID) => { 
      //some check code 
      if(err){throw err;}
      return(stockDeduct)=> { 
        //some check code         
        if(err){throw err;}
         return 
           printInvoiceLine(stockID, warehouseID, stockDeduct);     
      }
   }
}
function printInvoiceLine(stockID, warehouseID, stockDeduct){ 
 return stockID 
                + ' from ' + warehouseID
                + ' is reduced by ' + stockDeduct;
}
let orderItem298 = prepInvoiceLine('FN9382')('SOUTH')(2);

Conclusion

There are probably better applications for currying, but personally, I use it as a checking tool — especially when things need to be done in a particular sequence.

Another thing to note is that currying has the ability to repeat itself perpetually. But perhaps that’s for another time, as it’s beyond the scope of this article.

I hope this has helped clear up some confusion or frustrations that you might be facing in regard to currying.