Functional error handling in JS

The Good, the Bad and the Lambda

Tal Joffe
Nielsen-TLV-Tech-Blog
4 min readOct 14, 2020

--

source: animals.desktopnexus.com

(This article assumes a basic level of understanding of functional programming. If it is new to you I recommend checking this one first)

In code, as in life itself, s**t happens. And when it does, it is best to be prepared for it.

In JS, like many other languages, a common way to say that “s**t happened” is to throw an exception, and unlike real life, you have to catch that 💩 or you’ll crash and burn 🔥.

You might ask yourself, OK, we know that what is the big deal? Since the dawn of man, we have been throwing… stuff at each other. We throw exceptions in the code as well, and we just need to make sure we catch them. What is wrong with that?!

Well, here is what’s wrong:

  1. Exceptions are side-effects. FP ninjas don’t like side-effects.
  2. An uncaught exception will crash your application.
  3. The function signature doesn’t say if it might throw or not, so we have to be defensive and wrap everything in try/catch blocks.
  4. Testing thrown exceptions is a little funky (harder to do AAA)

— OK, we get we will stop throwing stuff around.. but what is the alternative?

🛤 Railroads

🤔 Railroads?

🛤 🛤 🛤 Railroads!!!

The most common way in FP to handle exceptions is to return an object that either has the success response or the error response (like in callbacks and promises).

I use promises as a native way to return success/response. In most FP libraries, this is done using an Either type.

Handling errors in this way is pure, declarative, and easy to test

Very simple to test errors using the AAA pattern

You can take this approach a step forward with a cool pattern called “Railway Oriented Programming.” Simply put, you chain your functions one after the other and handle success and failures in “different tracks” — unless there is an error returned, you continue on the “happy path.” Any error along the way will move you to the other (“sad”) path.

source: https://fsharpforfunandprofit.com/rop

If you ever used a promise chain with catch, it is one possible implementation of such an approach.

We chain our validations one after the other — if all went well, we reach the end of the “happy” track.

A few notes on the code I used in the example.

  1. I recommend working with Typescript as well which greatly improves readability and makes for a very clear function signature on what can be returned in case of an error
  2. In the chain, I always use named functions so it is very clear what is happening in each step. Here is a nice explanation of this approach
  3. Promise-chains as I said are a simple way to achieve my intentions. If you want to get a deeper functional explanation I recommend this article

So can I never again use try and catch? 🙏

Like any other tool, the ROP concept should be used in the right places. Generally speaking, it makes sense to be used in cases where you explicitly want to specify errors as part of your logic (like my validation example).

Since you use frameworks, libraries, and native functions that will possibly throw errors you still have to use try/catch in your code.

Here is a nice article on when not to use railway oriented programming (by the same guy who wrote the original concept, Scott Wlaschin)

Final note

ROP is obviously not the only way to handle errors, and there are ways to write maintainable code only with Exceptions. One such approach is to only handle exceptions at the uppermost level of your code so that you don’t need to use try/catch everywhere.

I personally find this pattern very helpful, and I like the fact that it aligns well with the functional patterns I love to use.

If you made it this far, thanks for reading, and may the Lambda be with you

--

--

Tal Joffe
Nielsen-TLV-Tech-Blog

Interested in software, people, and how to bring the best of them both @TalJoffe