Javascript: Maybe undefined or Not?

https://unsplash.com/@sabrit

I’m sure all of us have faced undefined instead of that sweet sweet data were expecting. Instead of just thinking of traversing the data structure and rendering it somewhere we now have to deal if that data will be there or not.

I’ve had problems in my angular app when the first change detection cycle happens and the state that is passed into my pure components are undefined.

My story is not exclusive to Angular2 components but you can also use this in React components, or any code that expects state that can turn up undefined. However, my examples will be using an Angular2 component and Typescript/ES6.

An Angular component receives state from its parent through the @Inputdecorator. The line of code below means that it will receive state through the @Input decorator and is expecting a type of List<any>. List is just a data structure from immutable.js that is sort of like a Javascript array.

I’m expecting a heterogenous list, meaning a list containing any type(numbers, strings, Map, List, etc.).

@Input() students: List<any>;

Let’s say the students list look like this:

[{
id: 123,
firstName: 'John',
lastName: 'Doe'
},{
/*more objects*/
}]

In my template, I access the structure like this in Angular2. With the *ngFor. It’s similar to a for loop or a map, and let’s access the id property by doing .get('id'). This should render the id value.

<div *ngFor="let student of students">
<p>student.get('id')</p>
</div>

That is fine and dandy and was really easy! Right… Then comes the real world. A delay in the api call, the database was down for a second, disks need to spin first, the data center got nuked, etc.. And all you wanna do is render the IDs of these students but now you have to deal with the real world. So this List of students can now turn up undefined and can cause your program to crash and burn. So, you write a lot of lines anticipating this event. More than likely these lines you’re going to write will be tied to this anticipated event and can be hardly reused.

We usually write an if..else..else ifor try/catch. This can get confusing, especially for other developers reading your code. They would have to step through your control flow.

What if there’s a better solution? Fortunately, there is! The Ivory Tower of functional programmers have handed down a solution to us, mortals. They call it a Maybe Monad or something like that. Something.. something category theory.

I googled for some metaphor or definition of a Monad. Some say it’s just like a Burrito, Space suit, etc. I also found this “simple” explanation

A monad is a monoid in the category of endofunctors

wuh??

A burrito is a tacoid in the category of enchiladafunctors

They said I don’t have to know its whole entirety, but it doesn’t hurt to study it. So all I have to know to use it is that it is similar to an Array. Like a container for values. I can operate on the values by using the methods it has. In an array, we can operate on the values by using the map, filter, etc.. methods. A Maybe also has its methods like map, of, chain, etc. Okay, the 2 operators of and chain sound unfamiliar. They do, we’ve seen them before they just have different names. of just puts a value into a Maybe, and chain is just like a map method. It takes a function then applies it to the value inside the Maybe then returns a value. The difference between chain and map is that map will return a value wrapped in Maybe(a)

Maybe.of(value)
// Maybe(value)
Maybe.of(1)
.map(addOne)
// Maybe(2)
Maybe.of(1)
.chain(addOne)
// 2

We can find a library that has implemented this in github or npm. It’s called data.maybe from folktale.js.

A Maybe can return two things Just value or Nothing. Just and Nothing has the methods so we can operate on the values. In Javascript, Maybe is implemented as the parent class and Just and Nothing extends it.

Let’s try and use it. Say, we’re expecting a number/s but it can turn up undefined. Most of us know what will happen if we try to operate on a number that turns up to be undefined. That’s right, NaN.

const isNil = n => n === undefined || n === null;
const maybeNumber = n => isNil(n) ? Nothing() : Just(n);
const addOne = n => n + 1;
const addedOne = maybeNumber(inComingNumber)
.map(addOne);

Okay.. When I first saw this my first reaction was, “It can’t be that easy”. Fortunately, it is. It works like this in our maybeNumber. If it returns Just(n) we can do:

Just(n).map(addOne) // out some number

If it returns Nothing

Nothing().map(addOne) // it simply won't perform map

Thus, not returning undefined or

TypeError: Cannot read property ‘map’ of undefined

Awesome! I don’t have to worry about handling those! Let’s go back to my Angular component that’s expecting to receive a list of students. But first let’s make our utility function:

import { List } from 'immutable';
import { isNil } from 'ramda';
import { Just, Nothing } from 'data.maybe' // * different in TS
export const maybeList = (list: List<any>) =>
isNil(list)
? Nothing().getOrElse(Just(List()))
: Just(list);
// .getOrElse is just a fancy method that sets a default value.
// In this case, I'm setting an empty List

We can now import this in different places.

import { maybeList } from './utils';
class StudentComponent {
@Input() students: List<any>;
  getStudents() {
return maybeList(this.students)
}
}

Right now if we call getStudents it will return Just(List()) or Just(students). It’s still contained in a Just, and I don’t think our templates or jsx can render Just(students). So we use one more method, the .chain method. This will take out the value from the Maybe monad and applies an operation to the value. But what if we don’t want to do anymore operation?

We can pass it the identity function like so:

// its a function that returns its parameter
export const identity = x => x;

Then import it into our component:

import { maybeList, identity } from './utils';
export class StudentComponent {
@Input() students: List<any>;
  getStudents() {
return maybeList(this.students)
.chain(identity);
}
}

In the template:

<div *ngFor="let student of getStudents()">
<p>student.get('id')</p>
</div>

The programmers from the Ivory Tower proclaimed that once a value or expected value is in a Monad you almost never want to take it out of there. So we do all our operations and just take it out if and only if we really need to, like in our case of rendering the data. So, if we ever want to do more operations on that students list we would want to do this.

getStudents() {
return maybeList(this.students)
.map(/*capitalize first names*/)
.map(/*some more operations*/)
.chain(identity);
}
// if you have two .map you can compose them into one, but that's
// for another article

No state was harmed in this article.
Show your support

Clapping shows how much you appreciated Ken Aguilar’s story.