loading...
Cover image for Class Contradictions in TypeScript vs JavaScript

Class Contradictions in TypeScript vs JavaScript

bytebodger profile image Adam Nathaniel Davis ・5 min read

React's Class Warfare (5 Part Series)

1) The class Boogeyman in JavaScript 2) Reinventing the Wheel With React Hooks 3) A Hooks-vs-Classes Report Card 4) When Should You Convert Your Classes to Hooks?? 5) Class Contradictions in TypeScript vs JavaScript

Lately, I've been noticing something... odd about the fanboy wars that continually rage in the JS/React/TS communities. If you've spent even a little bit of time writing JavaScript, or browsing through the online volumes of JS blogs and thought leaders, you may have noticed some of these trends over the last several years:

  1. JavaScript is all about functional programming. To hear some of the fanboys vent on the subject, you'd almost think that it's impossible to write JavaScript without adhering to a strict FP paradigm.

  2. As a consequence of this functional-programming obsession, classes - and JS's pseudo-class keyword - are bad. Really, really bad. Don't ask why they're bad. If you even ask such a question, you risk being ostracized. So rather than risking the fanboys' wrath, just quiet down and accept that classes are bad.

  3. A lot of the more-senior, more "hardcore" JS acolytes have (by my estimation) increasingly migrated toward TypeScript in the last 3-4 years. Sure - you're not required to write TS to be a "real" frontend/JS dev. But it feels (to me) like TS is becoming a much larger influence amongst the hardcore JS devs - the same devs who seem so deeply offended by the sight of the class keyword in any of their plain-ol' JavaScript code.

  4. The previous point is amplified if you're an Angular dev. Modern Angular has become, basically, a TypeScript library.

  5. When you start writing a lot of TS, and you start talking to a lot of those grizzled JS veterans who now prefer to code only in TS, they don't seem to have too many problem with class.

     

Wait... What???

 

JS Classes Are... Bad??

I won't repeat here all of my frustrations with the "typical" JS dev who wrinkles his nose at the class keyword, but believes anything inside a function is sublime. You can see those articles linked at the top of this blog series.

My only point (in this section) is to highlight the fact that, nowadays, if you're developing in React, or in vanilla JS, or in many other JS libraries, there's a good chance that some of your team members disdain classes - and love functions. And if you don't wanna be seen as the out-of-date dinosaur on the team, you'd better shape up and start cranking out more of those functions.

TS Classes Are... Good?? (Or At Least, Acceptable??)

And maybe I could get down with the whole idea that any use of a class keyword is somehow "wrong" - if it weren't for some of the glaring contradictions that I feel exist in the JS/TS code-sphere. Specifically, I can't figure out, for the life of me, why it is that a class - in JS - is somehow antithetical to the core idea of JS. But if you switch to TS (and all JS is TS), it's perfectly fine to start cranking out classes??

You don't have to take my word for it. Spend a few minutes googling React tutorials - especially, any tutorials published in the last two-or-so years. You'll see that many of them are heavily focused on functions. (Or... on the new "hotness" - Hooks!) Then spend some time googling the latest tutorials on TS. And repeatedly, you'll find yourself running smack-dab into... classes.

(Functional) Disclaimers

Before you get up-in-arms, please understand: I'm perfectly aware that classes aren't in any way required in TS. I've found numerous cases in TS where classes seem to be the "default" answer - or where, by my estimation, they just seem to be the "solution of least resistance".

But this isn't meant to imply that classes are required for TS devs. If you're a FP fanboy, and a TS fanboy, you can pretty much write all of your glorious TS code without ever having to reach for that mean, ugly, nasty class keyword. But I can't help but notice that, over and over again, I start researching "how to solve Problem X in TypeScript", and over and over again, the suggestions I find from the community are written with classes.

Historical Context

I'm pretty sure that I understand how this (perceived) dichotomy arose. JS is TS. So, on some level, you'd think that we'd have the same trends influencing both communities. But TS has a very strong lineage... from C#.

Now, don't start hoopin' and hollerin'. I fully understand that there are few similarities (under the covers) between C# and TS. But, syntactically, TS looks incredibly familiar to anyone who's coming over from the C# world. And that makes perfect sense, because TS is the logical spawn of Microsoft's previous involvement in the ECMAScript open-source community.

With all that in-mind, it makes perfect sense that TS and C# share (syntactic) constructs such as:

  • Classes
  • Interfaces
  • Decorators
  • <>-syntax type-castings
  • etc., etc.

But I'm still sometimes baffled to see how classes are increasingly shunned in the "plain JS React" community - but they seem (to me) to be much more tolerated in the TS-React community.

An Anecdotal Contradiction

I was inspired to write this because I have a friend. He's a dev, like me. But he's far younger than me. And he's, frankly, a far better dev than me - a real "whiz kid" type. He lives-and-breaths this stuff. While my experience usually allows me to hold my own in a conversation with him, I'll freely admit that he's already internalized much more deep knowledge about programming than I ever have.

This friend of mine is a pretty hardcore "class hater". He thinks that the keyword never shoulda been introduced to JS. If the JS code works perfectly - but it uses classes - he sees it as a central flaw.

In the last year-or-so, he started making the TS conversion. He was slow to adopt it - but once he did, he really "found religion" so-to-speak. I don't honestly think he wants to code in anything but TypeScript at this point.

But something fantabulous happened during his conversion to the TypeScript (Dark) side: Somehow, he's magically lost his aversion to JavaScript classes.

To be clear, he still hates classes in vanilla JavaScript. And yet, it doesn't seem to bother him when he sees classes in TypeScript. I've even asked him about this directly - and quite frankly, as much as I respect his overall skills, the fact is that he's offered nothing but lame platitudes to explain his continuing aversion to JS classes, all while he has no problem with TS classes.

Confusion/Conclusion

So, at this point, I don't really know what to say. I realize that some TS devs hate classes. And I know that some JS devs are perfectly fine with them. And maybe the only "problem" is in my own perception. Maybe the trends are not what I see from my old, cranky perch on the programming shelf. But if there is anything to my analysis, it just doesn't seem to make any sense why "hardcore" JS devs are so disdainful of classes - and yet many "hardcore" TS devs don't seem to have any problem with them.

React's Class Warfare (5 Part Series)

1) The class Boogeyman in JavaScript 2) Reinventing the Wheel With React Hooks 3) A Hooks-vs-Classes Report Card 4) When Should You Convert Your Classes to Hooks?? 5) Class Contradictions in TypeScript vs JavaScript

Posted on Jun 21 by:

bytebodger profile

Adam Nathaniel Davis

@bytebodger

React acolyte, jack-of-all-(programming)trades, full-stack developer

Discussion

markdown guide
 

I don't think you need to start cranking out classes if you're using TypeScript (TS). Maybe you're referring to Angular code? I've written a lot of React in TS and just plain TS and rarely used classes.

Classes are not inherently bad, it's just that functional programming has become more popular these days.

 
 

I agree. And that's why I said that you don't have to use classes - especially with React Hooks. But what I'm trying to allude to in the article (and perhaps I didn't do a good job of it) is what I perceive as the general attitude of React/JS devs vs. TS devs. As with the friend that I described at the end of the article, I know some "JS guys" who hate classes. And yet, when those same guys switch over to TS, their class hatred seemingly melts away...

Yeah I agree. In typescript people are more likely to uses classed compared to js.

 

I don't think es6 classes are bad, it's just syntaxic sugar over js prototypes. Having a mental model based on c#/java OO model in JS seems error prone to me. If you want to do serious sh*t with OOP you should learn and understand prototypes and not reproduce c# code. "this" in JS has a totally different meaning.

Having said that, IMO, except if you're stuck with Angular (in 2020 really ?), you should definitively get rid if OO in JS , especially with "this", and with inner state in classes, unless you fully understand what you do.

And if you use classes only to organize your code, maybe just use es6 modules with plain old functions !

 

A few thoughts:

I'm pretty neutral on Angular - but there's a lot of Angular out there. So it's not as though writing Angular code in 2020 is somehow... antiquated. But if I have my choice, I'll use React over Angular every single time.

With regard to this, like most JS devs, I used to have my share of headaches with it. But since the introduction of const and let, I can't honestly remember the last time that I ran into any kinda problem with this. In a class-based component, this simply refers to this class. But I understand that many people now are very leery of any use of this.

And with regard to "inner state in classes", if you're doing React, you can now use Hooks. But that just allows you to create a function - with inner state. So I'm still a little baffled sometimes by the people who rail against state in class-based components, but have no problem with useState() in functional components.

But none of these points are meant as any kinda "argument" to your comments. I hear what you're saying, and for the most part, I don't really disagree at all.

Thank you for the comments!

 

In my company (french insurance), we have a legacy codebase in angularjs (with es6 classes) and a New one in react (mainly with fonctional components). I can guarantee "this" led to many issues, especially with junior devs, and especially when bind () is used !

About inner state : Indeed, inner state aren't a problem in React (class based or functional components) because of React oneway dataflow. But when you write class based services, inner state Can be shared and you don't control where the mutations come from. With aggregates of pure functions, you can avoid those bad interactions.

I can guarantee "this" led to many issues, especially with junior devs, and especially when bind () is used !

I've put (I think somewhere else in this same post's comments), that, to me at least, I've always felt like the .bind() issue is a bit of a red herring - because, with class-based components, you never actually have to bind - ever. But I understand that there's a lotta legacy code using .bind() and, when I first started doing React, I was following the "official" examples and using it myself - but I hated it.

Of course, I realize that just because you don't have to use it, doesn't mean that people aren't still using it. And I realize that this causes confusion. It did for me, at first, until I learned to forgo it entirely.

But when you write class based services, inner state Can be shared and you don't control where the mutations come from. With aggregates of pure functions, you can avoid those bad interactions.

Well... inner state can be shared in functional components as well. I get your point. Entirely. But this issue isn't (IMHO) a class-vs-function issue. It's a "how do we manage shared state" issue.

As for pure functions, again, I basically agree with you. I will only add that, amongst some of my friends who are hardcore FP acolytes, they talk about "pure state" the way some people talk about "enlightenment". And I get it. The more pure functions you can write - the easier it will probably be to avoid nasty bugs down the line.

But the whole "pure functions" discussion is, to some extent, theoretical. Because any app that really does anything of merit will, at some point, have to manage state. If, for example, the user has logged in, you obviously must be able to "remember" the simple fact that the user has logged in. And you have to maintain that data... somewhere.

But again, none of these "points" are meant, in any way, as "arguments". I hear what you're saying. And I pretty much agree. I'm only writing functional components now. And I'm trying, whenever possible, to factor my code into pure functions wherever the logic allows.

Agreed ! you can do great things with classes, limit bad or risky practices, but unfortunately when you share your codebase with 1, 2, 10 or 100 people, you never know which level of care each of one will bring.

I agree, ultimately you have to put a state somewhere and fp purists are often very blurry about where to put it. Flux then Redux answered that in a interesting but verbose way. hooks allow you to use plenty pieces of state, it's so convenient and I love use them but still cannot convince myself it's the ultimate best practice!

 

There are pros and cons to both OOP (classes) and FP.

I find Anders Hejlsberg's musings on functional and OOP very enlightening. He talks about how they moved the original TypeScript codebase which was very OOP heavy (lots of classes) and over to a functional programming style with immutable data structures etc. I like his approach. FP helped solve some of their problems they were tackling so they embraced FP and went with it. I'm sure the same approach would have been used if OOP was a better solution.

Worth a watch :)
youtube.com/watch?v=7YDVbkvVXQM

 

Hejlsberg is always worth listening to. 👍

 

He's a pretty funny guy if you listen to some of his interviews. He always looks like he's having a good time.

 

The problem (at least in my case) is not with the class itself. Is with this.
If you are using classes, of course you use methods which change the state using this. And that can lead to a lot of frustration, and people need to use bind(this).

When instead of using classes with methods you start using pure functions the code is much much more clear and testable.

Also we create types using class (or better with type in TS), so classes cannot be ignored completely. But this doesn't mean that all code should be classes.

I recommend you to try to read this book, to see the things from the eyes of a FP fanboy:
mostly-adequate.gitbooks.io/mostly...

 

The problem with FP is that it's the same as OO. Devs like to get stuck on some philosophy and hate all others. Some of us like to mix and match. Just look at Scala, a lot of FP people hate it for using some OO. A lot of OO people hate it for being FP, and some of us love it for being just that, a free choice of 2 worlds.
Now as soon as you try to be reasonable and just get the work done it fires up crowd in development as theres popular belif that this is a job where you need to be smart, know math, and such, thus the need for philosophy and hate the people who think they're only humans.
"If it was up to engineers in automobile industry we would have no cars today".

 

I wish I could give this more hearts. This basically sums up about half of my blog posts. I understand that everyone will have preferences and, on occasion, we all find subjects on which we feel passionate. But for too many devs, they see nearly every architectural choice as an opportunity to enlist in another Holy War.

 

The binding issue has always felt like a red herring to me. There's no scenario where you must .bind(this). I haven't used .bind() in years. But I understand that, for those who don't know how to get around it, it's annoying. When I first started React, it annoyed the heck outta me.

I appreciate the link! I'm definitely checking that out.

 

I like your posts and your writing style, I really do. In other had I don't see your point that people don't have problem with classes in TS but they have it with JS. In my experience if somebody hate classes , he/she hates them in both.

Going back to classes vs functions, the problem is that you can make the same thing in both, but classes are tools which were stateful and effectful, where functions are stateless and effectless. It means that in order to replicate class behavior you need to have some third party who does the state part and the effect part. This is exactly what does for example IO Monad or React. React calls these functions and makes them a meaning. It means that effect is rendering and state is provided by hooks.

So we have real two tools for the same thing. That is why in one codebase you can find no classes, as it has different model of state and effect, where in other you have classes and OOP behaviors.

I am not against classes, but classes are OOP construct. And if your codebase have different way of solving problems. You should use this way.

Of course you can also use classes as some framework building block, and that was the React before hooks. What they did though is that they said it was not a great building block, and gave us alternative. You can argue with their decision. But if you have two tools for solving one problem, and one is recommended, then naturally you should probably pick this one.

Still not saying classes are bad, but everything depends from the context. It's a tool, can work for you or not, can be recommended building block or not. I am not a fan and not a hater. If I would go to some language like Java I would use classes, and I have no problem with that. But in React I would not.

 

At the risk of belaboring this point, I wanna mention that your comments here got me to thinking more about the whole classes-vs-functions thing. I'll freely admit that, if you read a lotta my previous articles (and I know you have), it's easy to come away with the impression that "Adam loves classes. And Adam hates functions." And that impression is probably my fault, with regard to my writing style.

But, in my mind at least, my "gripe" isn't really about any particular architecture/tool/library/approach/etc. It's about what happens when you are already using Technique A (and, by your estimation, it's working great), then someone comes along and says, "Technique A sucks. You should be using Technique B."

My "issue" here is probably best illustrated with a traditional, simple Venn diagram:

Alt Text

If Technique B completely coincides with Technique A, then the natural, logical response is to say, "Well, I'll just keep using Technique A." In other words, if you want to do something a completely separate way, but that separate way provides no benefits over the original way, then switching to the new technique is nothing but an exercise in compliance. It'd be like asking you to tear down your brick house because now, everyone is building their houses with cinder blocks - and cinder blocks are just sooooo much cooler.

Of course, it's rare that two different techniques perfectly overlap with each other, right? Typically, the old technique (Technique A) has at least some features that simply aren't accounted for in the new Technique B. Similarly, Technique B presumably has at least some features that simply weren't available in the old Technique A.

So here's the question: Should you swiftly jump to Technique B, just because someone says it's the "new" way to do things??

Well, the answer is usually: Maybe?

Specifically, you'll probably wanna examine whether the things you're gaining in Technique B are more valuable than the things you're losing in Technique A. If you feel that you're losing a lotta cool stuff in Technique A, and you're not gaining much benefit from Technique B, then you'll probably be at least somewhat resistant to adopting Technique B.

With React, a tangible example of this would be class-based lifecycle methods versus the useEffect() Hook in functional components. I'm sure that reasonable minds can disagree on this, but IMHO, useEffect() really kinda... sucks. Even if you agreed with me, does that mean you should ignore Technique B?? No. There are certainly other factors to consider as well. (For example, you've pointed out that Hooks seem to be the recommended way of going forward - and I will freely admit that this is a very valid consideration.)

And this isn't meant as (yet another) defense of classes. There are many other factors to consider aside from lifecycle methods versus useEffect(). But it is at least one valid factor.

As I stated in my previous reply, the simple fact is that, for better or worse, I've actually switched almost-entirely to function-based components. But my point in highlighting the Venn diagram logic is that, in my mind, this isn't really about the benefits of classes or functions. It's about what happens when the "thought leaders" want us to switch our entire process of development - but maybe the net benefits of that switch are not readily apparent.

 

I appreciate your comments!

In other hand I don't see your point that people don't have problem with classes in TS but they have it with JS. In my experience if somebody hate classes , he/she hates them in both.

I freely admit that this post is based firmly on my current perception of TS-vs-JS. And it may be true that my perception isn't accurate. Or it may apply only to the sites/teams/regions in which I'm active - I don't know. I've just found it strange that now with me diving into TS, I'm running into a whole lotta suggestions from people... to use classes. But that may not map to your experience, or anyone else's.

As for everything else you've written here, I'm pretty much in agreement with you. Despite what you might've picked up from my previous articles, I don't love classes. And I don't hate functions. In fact, for the last couple of months, I've been writing nothing but functions - and for the vast majority of stuff, I'm completely fine with them. In some cases, I actually prefer them.

Again - good comments all around.

 

Within the FP/OO divide, only those devs have a reason to fight the other side that don't master both paradigms.

If you master both OO and FP, then you know exactly what you are doing (and when to use which, even if it means mixing), hence you need not go berserk like a religious zealot or fanatic.

 

Classes are bad. Thats my opinion.

 

In order for all of us to gain anything from these discussions here, I think it worthwhile focusing more on facts and arguments than on personal opinions.

You are entitled to your opinion, but stating it here and then not caring to elaborate on it when kindly asked, is a bit futile and, allow me to say, doesn't make much sense to me.

 

I wasn't gonna reply to his original comment. On one hand, I completely agree with what you've written here. On the other hand, his simplistic "Classes are bad." comment really kinda perfectly illustrates exactly what I'm talking about with regard to the general attitudes that permeate this particular little corner of the Holy Wars.

If I wrote a JS program that somehow managed to successfully divide by zero, some JS devs would look at it and say, "Well, yeah, but... you used classes."

Yeah, absolutely. Well said.

The way I see it: When religion and fundamentalism creep into technological discussions, the victims are always the zealots themselves.

Asking or promoting whether to use OOP or FP is like asking whether to go by car or by foot. Why limit yourself to one? Why not use the right tool for the right job.

 
 

No because it's the same like trying to convince an iPhone user that the Pixel is better.