DEV Community

Cover image for How ts-pattern can improve your code readability?

How ts-pattern can improve your code readability?

Tauan Camargo on September 13, 2024

My First Encounter with ts-pattern A few months ago, I was reviewing a client’s codebase filled with numerous switch statements and obje...
Collapse
 
lexlohr profile image
Alex Lohr

It is interesting that the code of the comparison seems intentionally bad.

const stateMessage: Record<string, string> = = {
  success: "Operation was successful!",
  error: "There was an error.",
  unknown: "Unknown status."
};
const message = stateMessage[status] ?? stateMessage.unknown;

// ---

import deepEqual from 'fast-deep-equal';
const userName = deepEqual(
  apiResponse, 
  { status: 200, data: { user: { name: "John" } } })
  ? "Hello, John!"
  : "User not found.";
Enter fullscreen mode Exit fullscreen mode

Please try to compare on equal footing.

Collapse
 
tauantcamargo profile image
Tauan Camargo

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.

Collapse
 
lexlohr profile image
Alex Lohr

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.

Thread Thread
 
tauantcamargo profile image
Tauan Camargo

Thanks for advise

Collapse
 
gollyjer profile image
Jeremy Gollehon

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. 💪

Collapse
 
fkereki profile image
Federico Kereki

This is not the point, but code could be cleaner using the constant (K) combinator; I prefer naming it constant (value would be a valid alternative) to make code clearer:

const message = match(status)
  .with("success", constant("Operation was successful!"))
  .with("error", constant("There was an error."))
  .otherwise(constant("Unknown status."));
Enter fullscreen mode Exit fullscreen mode
Collapse
 
koehr profile image
Norman

Thanks so much for the link!

Collapse
 
koehr profile image
Norman

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.

Collapse
 
tauantcamargo profile image
Tauan Camargo

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.

Collapse
 
twocs profile image
Tom Anderson

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:

switch (true) {
case !p: return 536;
case p.status === fancy: return 1886;
case p.zip ===ts: return 12;
default: return 5;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
leob profile image
leob

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) !

Collapse
 
tauantcamargo profile image
Tauan Camargo

It does a lot more, I will make another post covering more examples, thanks for the comment

Collapse
 
rimbin profile image
rimbin

How big is the performance downgrade? It doesn't look as a zero cost abstraction.

Collapse
 
cugarteblair profile image
Carlos E. Ugarte

It would only matter if it were inside a loop

Collapse
 
justinmchase profile image
Justin Chase

I'd hard block this PR. You're gonna regret it massively later. Just use the simple syntactic approach.

Collapse
 
tauantcamargo profile image
Tauan Camargo

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.

Collapse
 
marcosjr182 profile image
Marcos Siqueira Junior

Can you elaborate a bit more on why would you do that?

Collapse
 
fenroe profile image
Fenroe

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.

Thread Thread
 
kenny_kuhner_5bcbe071910f profile image
Kenny Kuhner

Exactly

Collapse
 
dtasev profile image
Dimitar

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

Thread Thread
 
joshua_enfield_a6ea8e7c54 profile image
Joshua Enfield

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.

Collapse
 
martinfjant profile image
Martin Falk Johansson

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.

Collapse
 
tauantcamargo profile image
Tauan Camargo

Thanks for the comment, appreciate

Collapse
 
technvision profile image
Sohil Ahmed

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.

Collapse
 
wyattbiker profile image
wyattb

Just a weakness in that language. In modern programming languages it is a built in keyword and much more readable and flexible

docs.godotengine.org/en/stable/tut...

php.net/manual/en/control-structur...

doc.rust-lang.org/book/ch06-02-mat...

Collapse
 
adnanmushtaque profile image
Adnan Mushtaque

In coding, just like in driving games like Dr. Driving, efficiency and simplicity matter. When I was reviewing a client's codebase, filled with complex switch statements and object literals, it reminded me of navigating tight, chaotic streets. That’s when I discovered ts-pattern, which streamlined the code just like a well-designed driving path. Instead of cluttered switch cases, ts-pattern made everything clear and manageable, much like how Dr. Driving Official APK challenges you to navigate with precision. By cutting down unnecessary complexity, both the game and the library focus on smooth execution. Check out ts-pattern to simplify your TypeScript projects!

Collapse
 
giandidom profile image
gian-didom

«deeply nested if conditions,» --> a simple "if-else"... Just stop, this is making the code totally unreadable with little-to-no benefit...

Collapse
 
jyoung4242 profile image
Justin Young

Thanks for this article, i will be incorporating this package into my workflow!

Collapse
 
idrk profile image
Lucas Lamonier

In my humble opinion, you don't need an extra dependency and a long string of callbacks (reminiscent of .then era), you need better code formatting.

Collapse
 
tauantcamargo profile image
Tauan Camargo

Read this other article guys

Collapse
 
pengeszikra profile image
Peter Vivo • Edited

A simple switch return can solve this problem without need including any more dependency to our program.

const statusInfo = (status) => {
  switch (status) {
    case "loading": return "Loading...";
    case "success": return "Data loaded successfully!";
    case "error": return "Failed to load data.";
    default: return "Unknown state.";
  }
}
Enter fullscreen mode Exit fullscreen mode

My advice is: keep the package.json as small as possible.

Collapse
 
tauantcamargo profile image
Tauan Camargo

Thanks for the comment, yeah I know that… I don’t know if you read the title , how this can improve the readability … not how you can launch a rocket 😊 but hell yeah thanks for read it and commented

Collapse
 
kimhj profile image
Kim Jensen

As a old Delphi programmer I always tought that when I was programming in Java, everything was made complicated, Pascal have been around for a long time I was always thinking why didn't they look at the simplicity of other programming tools when they created Java.
Case(status)
Begin
True: do this
True: do this
End

Collapse
 
rsenna profile image
Rogerio Senna • Edited

Typescript should definitely have switch/match expressions (as opposed to statements). If ts-pattern was based on something like "true macros" (like, say, how it's done in Rust), I wouldn't mind it as much: the cost for this ts-pattern would be paid at compile (or, if you prefer, "transpile") time.

But with those closures being used far and wide I'm pretty sure everything is being done at runtime. And why would you do that just for the sake of making your code look arguably more "cool"...?

TL;DR If you want a better language, then use one. Typescript lacks switch expressions, and it's better to either accept it, or move on to greener fields...

Collapse
 
rsenna profile image
Rogerio Senna • Edited

By the way, this reminds me of a story.

Once upon a time, in a galaxy far away, I worked with this junior developer in a medium sized call center company...

One day he presented us his "masterpiece": a mechanism for storing Java bytecode in a relational database, which could be loaded dynamically later, and executed by our main web application.

It was really cool seeing him so happy. And it was very awkward for us. Nobody wanted to criticize his work.

But of course, we sent the whole thing later to the Big Stack in the Sky. We garbage-collected it, one might even say... And we did it very quickly, because what actually needed to be done did not require that monstrosity at all...!

That "solution" had many issues, such as difficult maintainability. From a security point of view, also a bit concerning. It mixed data and code in a very unholy union. It was a (very weird) solution for a problem that we simply didn't have...

That poor, naïve dev did not know better, but fortunately we did. He was trying to reinvent the wheel, which sometimes can even be useful, but certainly not in that case...

Collapse
 
jmccabe profile image
John McCabe

Probably not a great example as all it appears to be doing is getting rid of the 'break' statement that, in decent (IMO) languages, i.e. those not derived from C, isn't there anyway! Also, looks like someone has decided to try to make TS look more like Rust.

Collapse
 
kbirgerdev profile image
Kirill Birger

There are design patterns and principles that mitigate this issue.

If your code is littered with http status checks and other control logic, then it doesn't matter if you use one library, or ten.

It would be better to use object oriented design, and single responsibility principle to address these code smells.

Consider: you should have a Client class for every http API you are using. It is better to use performant, idiomatic code to implement the logic in it. You should then package up the responses in a nice, object oriented way that makes them easy to consume.

Adding custom syntax and functional indirection is rarely a good idea

Collapse
 
helix_pranay profile image
Helix Pranay • Edited

This would have been perfect if only its size is a bit less

Edit - Current npm package size = 417 kb

Collapse
 
c01nd01r profile image
Stanislav

The size of a published npm package is not the same as the package's usage size in an application bundle.
The approximate size when using the package can be viewed on websites like bundlejs.com.
For ts-pattern, it will be less than 2.5 kB (gzip)

Collapse
 
nguyenhongphat0 profile image
Hồng Phát

I would prefer using an object over switch/case:

({
  chrome: () => {},
  firefox: () => {},
  safari: () => {} 
})["chrome"]();
Enter fullscreen mode Exit fullscreen mode
Collapse
 
tauantcamargo profile image
Tauan Camargo

Go for it… ur app ur rules

Collapse
 
stevediaz profile image
stevediaz

This sounds amazing as I found it very much useful and informative to be honest.

Collapse
 
tauantcamargo profile image
Tauan Camargo

you are welcome. will be sharing here some useful tools and patterns that have been helping me a lot.

Collapse
 
wizard798 profile image
Wizard

Hmm, looks interesting, never heard about this, thanks for sharing

Collapse
 
tauantcamargo profile image
Tauan Camargo • Edited

you are welcome. will be sharing here some useful tools and patterns that have been helping me a lot.

Collapse
 
wizard798 profile image
Wizard

Thanks for that I'm advance, looking forward

Collapse
 
ironblossom profile image
Ishtiaq Mahmood Amin

I understand that the conventional examples are intentionally badly written, but the solutions made me feel, when you have a hammer everything looks like a nail.

Collapse
 
tauantcamargo profile image
Tauan Camargo

Dude, it’s basic examples just to introduce someone to the library, I’m not trying to create an article to explain how compilers works…. Wtf

Collapse
 
_32a24721f9b5e088c539d profile image
朱重迁

这里面跟rust里面的语法有点像

Collapse
 
craig_strickland_1701019c profile image
Craig Strickland

Appreciate the alternative. This seems more like a solution in search of a problem but the approach is a novel idea ... function chain conditional logic.

Collapse
 
abrahamortizu profile image
Abraham Ortíz

Install a complete library to replace the native switch… Why not?

Collapse
 
tauantcamargo profile image
Tauan Camargo

Simple, just don’t install 😊. I don’t know if you read the title , how this can improve the readability … not how you can launch a rocket 😊 but hell yeah thanks for read it and commented