Typescript - Button Color State with ADTs

Posted on June 22, 2020

I’ve seen enough typescript code that I can say that booleans are over used. We need to normalize the use of sum types and reserve the use of booleans.

There are not a lot of things that booleans can represent. Even something binary like the state of a light bulb can get confusing when it’s represented with a boolean. Should True represent the light bulb being off or on, which one should False represent? I’m sure with lots of comments it will be fine, but as we all know comments are not too effective in conveying information to other contributors.

Imagine this withtout comments, would you able able to understand what this code is doing?

Let’s go through a contrived example and deal with button color states and fake http states, and eventually convert it to use sum types.

We’ll be using bulma css classes in the example

The parent component

Equality checks with strings is definitely error prone but it looks like this is fine, especially for something small scale but imagine an actual application with so many more cases and so much more logic. Depending on booleans and string equality will be a source of great agony. What can help us here is the type checker! Even though typescript is not as strong as something like purescript or haskell it can still help a great deal.

With purescript we can do something like this

The ButtonColor type that represents all the possible colors the button can render can then be exported so it can be used in the colorToClassName function. With a fake http response, we can model it with a sum type and do a case match and transform that into our button colors.

By using types, the purescript type checker can help us verify our program. I’m using “verify” loosely here, I don’t mean formal verification.

After that long tangent let’s go back to typescript and see if we can recreate what we did in purescript, and let’s do it in react! Let’s start with the button component and model the possible color states of this button. For a detailed explanation on sum types in typescript, check out Guilio Canti’s article. In typesript, sum types are called discriminated unions. In order to determine which type is being matched in a pattern match it needs a discriminant. We’ll be using the tag field as our discriminant. This is used in our “poor man’s” pattern matching, which is a switch statement.

Since I don’t like using switch statements, let’s modify the code a little bit using the Option type, specifically the utility function fromNullalble and it will come from the library fp-ts. We’ll also add the className field to the interfaces.

fromNullable transforms it into an Option type which is another sum type with None and Some<A> as its inhabitants. If we access a property that is not available in colors it will go to the getOrElse function and return noColor, otherwise it will match a color then access the className property.

Now, let’s look at the parent component and model the fake http response into something we can understand or something that makes sense in the context of the app, and transform that fake http response to a button color.

Success, Error, and Warning are the possible states for our fake http response here. They are then used in Response to form a union of all possible states of a fake http response.

As a result we have eleminated booleans in our tiny app and made the possible states of button colors and fake http response more explicit. We didn’t have to figure out whether True would mean “blue”, “red”, or “yellow”. We didn’t have to write long comments explaining how booleans would represent our fake http response.

Acknowledgements

Functional design: Algebraic Data Types - Guilio Canti

fp-ts

Example Repo

Button States