Introduction to Option and Either types in JS : Part 1

The goal of this post is to present a case for using Option and Either types in your JavaScript code base.

I will endeavour to convince you and your colleagues that there is benefit in using Algebraic Data Types such as Option and Either types in your code, even if you are using a dynamically typed language such as JavaScript.

Let us begin with a concrete problem and gradually work our way backwards into understanding why it would make sense to use them. We will be implementing a simple Option and Either Type along the way.


Wait… Why are you implementing your own Option types when there are existing libraries in the wild?

By implementing Option and Either types ourselves, our team had the opportunity to learn about its internals, rather than diving head-first into monads and functors. I certainly had a better understanding of how map or fold works because I could easily refer to the files within our code base!

Existing Libraries

Alternatively, if you are interested in existing implementations out there, check out:

If you are interested in implementing your own, you should also definitely check out Fantasy Land, which is a specification for Algebraic Data Types in JavaScript.

Regardless of which implementation you use, I hope that this post gives you a better grasp of the concepts which are transferable across different implementations.


Problem: Parsing Data

Imagine that your app has fetched some data from an API and returned the JSON response below:

Task: Display the value of bedrooms in the UI

However, any of the properties below may or may not exist:

  • listing
  • listing.features
  • listing.features.bedrooms

Rules

  • If bedrooms.value does not exist, return zero

Define getBedrooms as a function

The code above helps illustrate a simple problem: having to null-check values when accessing properties. We have to do so every step of the way, potentially littering our code with many ifs.

Forgetting to do so will throw a run-time error.

Looking at this from another perspective, you could argue that the problem is that we are trying to access or operate on values that may or may not exist.


Cruising through nulls with Option Types

The term Option type is borrowed from Scala’s Option, which is used to represent values which may or may not be present. In Haskell, it is known as the Maybe type.

Where a is just an arbitrary type that exists

When you store a value in an Option type, it could either be a:

  • Some, i.e. it is a non-null value
  • None, i.e. null or undefined

Instead of operating on a value directly, wrapping it in an Option, making it a Some or None, allows us to pass it a function, f, which is invoked on the value if it is present.

Option Type Definition

The code above is a basic implementation of Option that will help us get along our merry way towards reducing complexity.

What does map, flatMap, and fold do?

There is an important but subtle difference between map and flatMap, and that is the type of function you pass to it.

The map function takes a function which transforms a value into another value.

f: U => V

// Example
maybeAValue.map(x => x * 2)

The flatMap function expects a function which returns a Some or None.

f: U => Option<V>

// Example
maybeAnID.flatMap(id => getSomethingWhichMayNotExist(id))

On the other hand, fold can be used to extract the value held within an Option type. When you fold an Option type, you are forced to acknowledge that the value within may or may not exist. This is why fold expects two functions – one for when it is a None and one for when it is a Some. For example:

ifEmpty — evaluated if the value is a None
Option(null).fold(() => 'Empty!', x => x); // 'Empty!'

f — applied to the value within if it is a Some
Option('Something').fold(() => 'Empty!', x => x); // 'Something'

The illustration below is my attempt at explaining the differences, inspired by Functors, Applicatives and Monads in Pictures.

Let us put Option types to use by refactoring getBedrooms!

Refactor getBedrooms to use Option Types

This is our original code from earlier with all the null checks

Now that we know about Options, we can use them to wrap data.listing, which can be null.

In getBedrooms above, we use Option to wrap data.listing, which could be null.

If listing does exist, we access listing.features, which again could be null. We use flatMap to keep chaining our accessor functions until we get to bedrooms.
We finally retrieve the value by fold-ing by providing it with two functions:

  • () => 0, used if we have a None
  • v => v, used if we have a Some

Pros & Cons of Option Types in JavaScript

👍🏻 Signals the fact that a value could be null. If you receive an Option as a value and wish to operate on it, you would have to fold it. It is a nice way of enforcing the consumer to handle both a None or Some if it wishes to use the value.

👍🏻 Makes it easy to chain functions and not worry about null checking at all. This can be pretty powerful once you get used to the concept. It really encourages you to think of problems from a different perspective.

👎🏻 Can be verbose. Looking at the initial solution without Option types, you could argue that it has less lines.

👎🏻 We cannot fully harness the power of Option types without typing our values. Part of the definition of map or flatMap requires the arguments passed in to conform to a certain signature, e.g. flatMap: U => Option<V>.

JavaScript, being a dynamically typed language, does not have the mechanism to tell you if you have a type error until run-time. Despite having mad love for JavaScript, I really see the benefit of having a 100% type system.

Our team has been been taking incremental steps to introducing types to our codebase using FlowType, a type checker. This has allowed us to slowly spread types across the codebase as we become more comfortable with them and improve our type signatures.

I see several benefits to adding types to our JavaScript codebase:

  • Familiarity with types in general
  • Expressing our intent and providing more context in our code
  • Staying within the confines of JavaScript

With FlowType we are able to statically check our Option Types, which actually turns a 👎🏻 into a 👍🏻!

I recommend watching this talk from React Conf 2017, Type Systems Will Make You a Better JavaScript Developer by Jared Forsyth, which does an excellent job explaining type checking and type systems.

👎🏻 An additional layer of abstraction to solve a problem.

Option types are a foreign concept to JavaScript, unlike in Scala and Haskell where they are an integral part of the language.

Every abstraction incurs a mental cost to us as developers. You could argue that there are less complex ways of tackling this problem, e.g.

I believe that Option types, and any other Algebraic Data type, are not just another abstraction. They are concepts which are applied in functional programming to help eliminate complexity by increasing readability and the ability to reason about your code. Over time, just like understanding traditional code design patterns, using Option types will change how you go about solving a problem, as you might see recurring patterns and consider using them to reduce complexity.


Thoughts

Option Types are useful to represent data which may not be present. It might not be the ultimate silver bullet to all of your problems, it has its setbacks and limitations in JavaScript land, but I encourage you to consider them the next time you think about optional values! They have the added 👍🏻 of working together as a concept with other Algebraic Data Types, as you will see in part two where we explore Eithers – Introduction to Option and Either Types: Part 2.

References

Recommended readings:

Recommended watchings: