Sum types, the missing data structure
Popularized in JavaScript by some libraries like Redux, the sum types are a data structure representing values with different cases. Native in most functional languages, sum types are unfortunately not a builtin feature in JavaScript. We will recall what are the sum types and show how to use them in JavaScript.
Sum types
A sum type represents an “or” of values. Anytime we write a function which can have different kinds of arguments or results, we are using a sum type. For example, a function which returns either a number
or a string
message (in case of error) returns a sum type. The sum types complement the product types such as Array
which are “and” of values. In JavaScript, one way to encode a sum type is to use an object with a type
field. For example, the following function attempts to parse a string and returns either an error message or a number:
We can use the sum types to represent the result of an API call, the Redux actions, the routes, the state of a form (submitting, with an error, …) or the status of asynchronous requests (pending, successful, …).
The type
field helps to discriminate among the different cases. This is the difference between sum types and union types. In union types, we do not know to which case corresponds a value (unless we use introspection). Here is the same example with a union type:
In some senses, we can view a sum type as a union type plus a tag.
Should we prefer union types?
I believe that union types are dangerous. Indeed, if we look at the typing rules, union types are ambiguous while the typing of sums is syntax-directed. Moreover, with the notion of union comes the notion of inclusion of types, and complex questions such as the contravariance and often the need of downcasts.
Destructuring
There are no built-in ways to open the value of a sum type in JavaScript. We can use the switch
statement as proposed in the Redux documentation:
An other way is to use an object of functions:
For each possible case we define a function of the corresponding name and an optional default value.
Typing sum types
The JavaScript type-checker Flow has a good support for the sum-types, with destructuring in the form of switch
statements (see disjoint unions). Remember that, if needed, we can transform a switch
into an expression by using an empty anonymous function:
This is a bit heavy, but this is type-checked! The TypeScript system does not have sum types yet, but may converge to the same solution as Flow. If you are ready to change your syntax a bit more, PureScript and Elm have builtin supports of sum types with specific syntaxes for destructuring.
Comments