Maybe you should use maybes

Maybe is a type that wraps optional values. It’s a small JavaScript library, inspired by Haskell’s Maybe, Swift’s Optional and Scala’s Option.

It’s a better way of handling null and undefined. Instead of writing an if statement, ternary expression, or && shorthand to check if a value is present you can just map over it instead and assign the result of this expression or return it. You can also chain operations together, often leading to much cleaner code.

See the project Readme to get started quickly.

Why did I create it?

I’ve only been using JavaScript in anger for the better part of 11 months — purely in the context of React Native. In truth it was probably one of the first languages that I was exposed to because of the web and growing up as a 90’s kid, but back then my knowledge of it didn’t extend much beyond the alert() function, onClick() handlers and fancy menus with hover states.

More recently, I’ve been making apps in Swift and before that, Objective-C (hurrah). I’ve also built backends in Scala where I was trying to escape Java and needed a better way of dealing with asynchronous code (Future’s are like the JavaScript Promise — more on this later).

I have really enjoyed writing modern ES6/7 JavaScript compiled using Babel. For the most part I was happy with all the niceties, similarities and also differences.

Also, like React Native itself, I have embraced flow which I’d strongly recommend, although I have a bias towards statically typed languages.

What became obvious after a few months into a sizeable project is that dealing with null and undefined in JavaScript became tedious at best. Most modern languages have invented ‘better’ ways of dealing with null values and having just come from using some of them, I was feeling the pain of not being able to write simpler code to handle these cases.

I often think that programmers are particularly good at dealing with pain. They overcome hurdles on a daily basis and bang their heads against a wall until it just works. Over time they will forget why they are doing something a certain way, other than the fact that it didn’t work any other way.

“The most dangerous phrase in the language is,
‘We’ve always done it this way.’” — Grace Hopper

The main problem with dealing with null values like you would in Kernigan & Ritchie’s C is that your control flow is very constrained to writing statements instead of expressions. Every time you have a possibly null or undefined value you need to write an if statement to accompany it. Sometimes you can get away with using the && shorthand or a ternary expression. This might just be fine if you have to check only one value, but what about two, three, or five even plus some extra logic in there too. Eventually things get out of hand and you end up with some nested nightmare that others have coined the ‘pyramid of doom’.

This is very similar to the problem JavaScript faced when callbacks were the only way of representing asynchronicity, leading to the infamous ‘callback hell’.

The Promise abstraction was the answer to this, quickly followed by the async function variant.

‘Wait!’ I hear you say. I can just use some handy utility function to reach inside of my data (and also provide a default). Well you could, and that would be your choice, but what you’re forgetting is that these functions usually take a string or Array<string>. This is fine if you want to live by the seat of your pants. But if you’ve already committed to making your application typed using flow then this won’t give you any safety guarantees, or provide an easy path for maintenance either. You’ll have a stringly typed mess rather than strongly typed code.

What is interesting about the Promise in JavaScript is that it’s very similar to Scala’s Future conceptually — replace then() with map() and you’re most of the way there.

The thing that hasn’t quite caught on yet in JavaScript, but has done so in other languages is using this style of coding for optional values. In Swift, if I have an optional value then as well as conditionally unwrapping it with the if let syntax, I can also (optionally) transform it using the map function.

By promoting primitive null and undefined values to object types that have member functions — by wrapping them in a containing object — we can achieve something that resembles this paradigm.

JavaScript programmers should be familiar with most of the functions available on Maybe because they’ve already been using them with Array.

Ways to use it

I’d recommend checking out the project Readme for some simple examples.

In practical terms there’s no limit to its usage. I’ve seen it adopted by my team in these areas so far:

  • Components
  • HOCs (Higher-Order Components)
  • Redux (actions, reducers, selectors & middleware)
  • Api client
  • Other utility and transformation functions

The future

It becomes easier to use something like this once it’s supported at the library level and by the ecosystem. For example, you can’t return a Maybe type in render() of React’s Component just yet.