Why pure functions are just better in TS

When writing code in TS there are various design choices and patterns that we use, some occurring on purpose and others just happening with little or no thought.

One such example is “pure functions” a concept from Javascript that is in my opinion, even more important in Typescript.

Pure functions are a simple concept that can be summed up as:

Functions that always produce the same output, based on the same input

There’s more to it than that of course.

Additionally, it does not rely on any underlying state or data changes during the functions execution.

But most importantly: It does not produce any observable (often unwanted) side effects.

This last part is important! It’s exactly why I believe it to be a worthy goal to strive towards particularly when working with Typescript.

Let’s zoom out a bit!

What makes TS better than JS? Sure, it offers a better developer experience and offers early feedback on code, but most importantly it allows us to ship code with higher confidence.

Confidence.

Confidence describes exactly what makes TS better, because higher confidence means peace of mind.

As developers at the end of the day, we are paid to ship working code, and the higher the confidence the more we can trust our code is exactly that; working.

When we are not producing side effects that can cause undesired behaviour, we can rely on what we produce to behave how it should.

How a pure function might look

So, how do we write them?

Here’s an example of a classic pure function, written in Typescript for good measure:

function calculateSum(a: number, b: number): number {
  return a + b;
}

Now, of course this function does very little and therefore we can rely on it to behave consistently.

But more importantly, this function only performs actions on its input arguments!

So what may an impure function look like?

Impure functions come in many shapes and forms, and the common theme is working with things that can take an arbitrary shape or change over time.

Some examples are:

  • Working with HTTP requests or 3rd party APIs
  • Mutating data, like interacting with the database
  • Working with the DOM (which could change, and often does, especially with how modern JS frameworks work)
  • Math.random() (ok admittedly this one is a bit thought up..)

So why am I listing this, somewhat obvious list of things that encompass a pure function and its opposite?

Because I want to change your mind. I want you to see pure functions as the GOAT of Typescript. Javascript being a functional programming language, lends itself to all the advantages – and downsides – of how well our functions are written.

Or how poorly they are written.

So give yourself all the possible advantages you can and start writing more functions as pure functions!

Go through your existing code and try to identify functions where you make implicit assumptions about the available data or state of the application, and refactor it.

Here’s a couple of patterns you can look for and their respective refactorings:

  • Large functions doing many things: Extract things into separate functions, each ideally being pure and doing only one thing.
  • Functions relying on underlying available data: Extract into separate functions that takes the necessary data as arguments

There are many more examples when we can refactor with simplicity and purity in mind, but this should get you started!