How many bugs that you fix are a result of a null or improperly handling of an Error? In Javascript, it is very common to see errors like this: cannot call x
of undefined. 😞 While types help solve this problem within your own code, often times you have to use other libraries.
Using the Either ↔️ type, you can create safer algorithms, and make other library code safe for your application. The Either ↔️ type is a wrapper or container around a value, and the container comes in two instances, a Right
➡️ or Left
⬅️. In a pipeline, the Right ➡️ instance continues down the processing pipeline and the left does not. Using the map
and chain
methods we can create an Either ↔️ pipeline that takes an initial value and returns a result that is contained in a Left ⬅️ or Right ➡️ instance, we can get the value of the container at the end of the pipeline by calling the fold
method.
Either.of(1)
.map(add(1))
.map(multiply(2))
.fold(
v => console.log('Left: ', v),
v => console.log('Right: ', v) // Right: 4
)
In this example, we are taking the value 1
and putting it in an Either ↔️ container, then mapping over that container with transformation functions. The first function adds 1
to the value in the Either ↔️, and the second map has a function that multiplies the new value by 2. Each one of these functions is not checking if the value is not a number. The add function and the multiply function is depending on the Either to always give it a value with the expected type. So let's use a chain function to verify that the value is a number.
Either.of(1)
.chain(isNumber)
.map(add(1))
.map(multiply(2))
.fold(
v => console.log('Left: ', v),
v => console.log('Right: ', v)
)
function isNumber (v) {
if (is(Number, v)) {
return Right(v)
} else {
return Left('Not a Number')
}
}
By adding the chain method, we can pass another Either ↔️ Instance as the result of the function, this allows us to change the Either ↔️ from a Right ➡️ to a Left ⬅️ if the value is not a number, if it is a Number we can return a new Right ➡️ to be the container. This gives us the ability to safely run the add and multiply methods, because they will only run in the container, if the value passes the isNumber check.
Lets try a sad case:
Either.of(null)
.chain(isNumber)
.map(add(1))
.map(multiply(2))
.fold(
v => console.log('Left: ', v),
v => console.log('Right: ', v)
)
function isNumber (v) {
if (is(Number, v)) {
return Right(v)
} else {
return Left('Not a Number')
}
}
You will notice, that the add and multiply functions never get called. They are skipped because the result of the isNumber function is a Left ⬅️ instance.
With this pattern you can make any function safe. There are two common either functions: fromNullable
and tryCatch
.
fromNullable
fromNullable
tests if a value is null
, if it is not null, then it returns a Right
➡️ if it is null it returns a Left
⬅️.
Either.of(null)
.chain(fromNullable)
.fold(
v => console.log('Left: ', v),
() => console.log('does not get called')
)
tryCatch
tryCatch
takes a function and wraps a tryCatch around that function, if an error is thrown it returns a Left
⬅️ with the Error
, if there is no error, it returns the result of the function.
tryCatch(() => {
throw new Error('Catch me if you can!')
})
.fold(
v => console.log('You got me'),
v => conosle.log('You can\'t catch me, I am the gingerbread man.')
)
Demo
Summary
The Either ↔️ type gives you a powerful tool with common functional semantics to handle nulls and errors within you logic pipelines. This pattern empowers you to write safer code without injecting validation logic in every function you may compose.
Using Deno
? checkout this package: https://github.com/hyper63/either
Example Project
Check out the example project here:
https://github.com/hyper63/either-examples
NOTE: The example code is run using Deno 1.7, but you could use Either with the browser or NodeJS
Photo by Brendan Church on Unsplash