My First Encounter with ts-pattern
A few months ago, I was reviewing a client’s codebase filled with numerous switch statements and object literals spread across many files, which was making the readability and maintainability a mess.
During a pair programming session with my teammate Erick, he shared his screen and showed me a library that he was testing out.
That was my first experience with ts-pattern 🤩, and honestly, it blew my mind! The improvement in readability and maintainability was incredible.
Here is the link for ts-pattern documentation.
Let me show you some use cases where ts-pattern can make a real difference. One of the first questions I had was: Can I use this in any TypeScript project? The answer is YES 🙌.
Use cases
1. Replacing Complex Switch Statements
Traditional switch statement:
const status = "success";
let message;
switch (status) {
case "success":
message = "Operation was successful!";
break;
case "error":
message = "There was an error.";
break;
default:
message = "Unknown status.";
}
console.log(message); // Output: Operation was successful!
Using ts-pattern:
import { match } from 'ts-pattern';
const status = "success";
const message = match(status)
.with("success", () => "Operation was successful!")
.with("error", () => "There was an error.")
.otherwise(() => "Unknown status.");
console.log(message); // Output: Operation was successful!
Comparison:
Readability using ts-pattern is clean, no need for break statements, and pattern matches focus directly on the cases. Adding or removing conditions in ts-pattern is easier, and you don’t have to deal with the traps of forgetting breaks in switch cases.
2. Object Matching for API Responses
Using object matching:
const apiResponse = {
status: 200,
data: {
user: {
id: 1,
name: 'John',
},
},
};
let userName;
if (apiResponse.status === 200 && apiResponse.data.user.name === 'John') {
userName = "Hello, John!";
} else {
userName = "User not found.";
}
console.log(userName); // Output: Hello, John!
Using ts-pattern:
const apiResponse = {
status: 200,
data: {
user: {
id: 1,
name: 'John',
},
},
};
const userName = match(apiResponse)
.with({ status: 200, data: { user: { name: "John" } } }, () => "Hello, John!")
.otherwise(() => "User not found.");
console.log(userName); // Output: Hello, John!
Comparison:
ts-pattern reduces the need for deeply nested if conditions, making the logic cleaner and smoother. The pattern matching directly reflects the structure of the object, making it easier to understand and modify.
3. State Management
State management using switch:
const appState = { status: "loading" };
let displayMessage;
switch (appState.status) {
case "loading":
displayMessage = "Loading...";
break;
case "success":
displayMessage = "Data loaded successfully!";
break;
case "error":
displayMessage = "Failed to load data.";
break;
default:
displayMessage = "Unknown state.";
}
console.log(displayMessage); // Output: Loading...
Using ts-pattern:
const appState = { status: "loading" };
const displayMessage = match(appState.status)
.with("loading", () => "Loading...")
.with("success", () => "Data loaded successfully!")
.with("error", () => "Failed to load data.")
.otherwise(() => "Unknown state.");
console.log(displayMessage); // Output: Loading...
Comparison:
ts-pattern simplifies state management by eliminating the need for repetitive case and break statements. As the number of states grows, ts-pattern scales better with fewer chances of logical errors.
By comparing switch statements, object literals, and traditional conditionals with ts-pattern, it’s clear that ts-pattern offers a more elegant and scalable approach. Whether you’re handling complex states, object matching, or validations, ts-pattern reduces boilerplate code, improves readability, and minimizes potential bugs. Give it a try.
Will try to be more consistent in posting articles here 🤪. Thanks.
Top comments (53)
It is interesting that the code of the comparison seems intentionally bad.
Please try to compare on equal footing.
Yeah dude i know you cna do it, I don't know what you guys are interpreting, where did I say that this was the best solution? The most efficient?
Dude, I'm just reporting a library that I thought was cool.
Anyway, thank you very much for taking the time to read the article and for the comment.
I know from experience that good examples are difficult, but if you do a before/after, make sure to optimize the code on both sides or it is going to look insincere. Or even better, avoid it and skip the "before" part. If the example cannot convince without the contrast, you should take the time to find a better one.
Thanks for advise
As reading i was thinking the same thing regarding object switches.
What i hadn't ever thought about was using deepEqual in that way. Thanks for the idea. 💪
There are for sure some pretty opinionated comments in here. Some people are very quick to dismiss this as bloat for syntactic sugar. But this is not the case and that becomes clear, as soon you read the whole article, and the author could maybe have made this a bit clearer as well:
The major problem with switch statements is not lack of readability, but verbosity paired with very limited use. ts-pattern "fixes" that with an expressive syntax that can do more than a switch statement and is as powerful as a full flegded if-else cascade would be. Additionally, and this is more important in my opinion, it supports exhaustive checking, which a switch statement would only support with very explicit typing (i.e. using a result type).
Btw, the library is only 2.5kB according to Bundlephobia. No idea, how some commentors came to the conclusion it would add hundreds of kilobytes to your bundle.
I really recommend checking the examples on github.com/gvergnaud/ts-pattern before judging the library and even more to incorporate the intend of the author before judging the article.
Thank you so much for the advise, and to took a time to read, as English is not my native language I’m using this to improve my self,I’ll try to add this items that you mentioned on my next articles. ❤️ appreciate that you understood what I was trying to share here.
This is not the point, but code could be cleaner using the constant (
K
) combinator; I prefer naming itconstant
(value
would be a valid alternative) to make code clearer:Thanks so much for the link!
A lot of people who complain here must've never ever used a language that has pattern matching. While one can question whether you need add extra dependency, you technically never really need one. You do not need react, express or vue. Occasionally you might want to add something that makes different patterns possible, and this looks like it would make a functional style pattern matching possible (switch does not, mind you).
I get the feeling that the very negative seniors are old OOP-java people that refuse anything that is newer than 10 years ago. Jeesh, give the guy some slack. He did write something and it's not AI slop or a top ten. It is entirely possible to say that you would not use this in a job setting whilst at the same time not being overly negative nor implying that the author is an idiot.
Thanks for the comment, appreciate
I'd hard block this PR. You're gonna regret it massively later. Just use the simple syntactic approach.
I don't know what you guys are interpreting, where did I say that this was the best solution? The most efficient?
Dude, I'm just reporting a library that I thought was cool.
Anyway, thank you very much for taking the time to read the article and for the comment.
Can you elaborate a bit more on why would you do that?
Eventually someone is going to review the code base for improvements and notice a package is being used to basically make switch statements look cuter. After an initial bout of confusion, a ticket will be added to refactor all instances of ts-method into switch statements. Not only is this package unnecessary, but it reflects a tendency of one of the developers to introduce useless packages to the project, and those useless packages will eventually start taking a toll on performance and upkeep.
Exactly
If's and switch'es will be there in 10 years. There's no guarantee ts-pattern will be there in a month. That's enough to bar it from touching any sensible production project.
Apart from that it's somewhat pointless semantic sugar that makes it harder for another developer to pick up your code and adds extra size to your app.
Could be fun for some standalone or amateur project, but I doubt any senior developer will, nor should, allow this in
If and switches may be, but Typescript may not 😆 core frameworks often change major paradigms over a decade. The extra size is probably nominal. Abstractions are everywhere. This isn't a major framework.
I personally feel that switch statements, especially the ones posted above, are fairly readable. However, the main thing that packages like ts-pattern (and proposal github.com/tc39/proposal-pattern-m...) contribute is improved pattern matching with type safety. JavaScript only supports primitive types for switch statements, so a workaround for more complex comparisons has been to use:
How big is the performance downgrade? It doesn't look as a zero cost abstraction.
It would only matter if it were inside a loop
The way it "reads" is nice, but I can't help but notice how incredibly simple it is, lol ... is this all there is to this library, or does it do more?
I do like the coding style though - something like this should just be baked into JS (or into TS, haha) !
It does a lot more, I will make another post covering more examples, thanks for the comment
Thanks for this article, i will be incorporating this package into my workflow!
Not on a ts tech stack but im sure this will be a performance downgrade somewhere cuz js need to be written in the same way and that js will get much complex if the ts code is something of work all by it self.
Not to mention build time will also suffer.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.