Delve into the intricate world of pattern matching and discover its profound impact on code efficiency and expressiveness.
homeowners communities managed
of property managers in Spain using it
reduction of banking cost for communities
Industry
Use case
Location
For frontend development at Swan, we use TypeScript, a typed superset of JavaScript that, in our opinion, needs no introduction.
The downside of using TypeScript is that it deprives us of several paradigms that are absent in JS and that we may be accustomed to using when we worked with other languages in the past. One of the biggest shortcomings for us is the lack of pattern matching (it's currently being considered, but still in draft).
Yes, pattern matching.
Let's imagine that we want to describe the loading state of a request, which can be uninitialized, in progress, successfully completed, or completed with an error.
Naively, we could write it as follows:
As you can see, this code is hard to read and maintain, and is also prone to errors: what happens if a setUser((prevState) => ({ ...prevState, user: newRandomUser })) sneaks into your code? You could end up with the user state similar to { isLoading: false, data: newRandomUser, error: previousUserError }, an impossible case for our UI.
Fortunately, TypeScript offers us a solution to this problem with discriminated unions: unions of object types with a common property (the discriminant) allowing us to determine which kind of shape our value has.
Let's refactor our previous code using discriminated unions:
Aaaah, much better already!
However, a few problems still remain:
ts-pattern is a pattern-matching library for TypeScript developed by Gabriel Vergnaud. It allows you to compare an input value against different patterns, execute a function if it matches, and return the result. Consider this example:
As you can see:
Swan exposes a GraphQL API, so it’s quite easy to leverage pattern matching to consume our API, and it’s not only for the frontend!
Let's start by generating an SDK using GraphQL Code Generator and write a GraphQL operation:
The generated return type is a discriminated union, similar to the one we wrote before:
So we can consume it like this:
Since the matching is exhaustive, you will be notified of any new rejections added in the API updates and you will have to update your code to handle them accordingly. If you wish to ignore this, you can use .otherwise() instead:
Of course, we are only scratching the surface of what is possible. To delve deeper, you can visit the documentation of ts-pattern, explore our frontend codebase (where we even use pattern matching to handle results returned by our router) or clone and experiment with the latest example repository.
Have fun!
Summary
Customer stories