DEV Community

Cover image for Tossing TypeScript

Tossing TypeScript

Adam Nathaniel Davis on July 27, 2020

I don't need TypeScript. There. I said it. Honestly, it feels pretty good to finally assert that on the record. And if we're all being honest w...
Collapse
 
dvddpl profile image
Davide de Paolis

You shouldn't create forms that will "break" if the user provides bad data. And you shouldn't create functions (or methods, or components, or classes, or... whatever) that will "break" if another programmer invokes them with bad data. Period.

Thanks for writing this.
Awesome article

Collapse
 
bytebodger profile image
Adam Nathaniel Davis

You're welcome! I'm glad you enjoyed it!

Collapse
 
phantas0s profile image
Matthieu Cneude

Wow. I don't write JS (and I don't really want to), but I still read this article from top to bottom because... it's good.

  1. It's well written, precise, and detailed.
  2. I'm always happy when somebody comes back to the real meaning of interface. It's an important concept, but everybody is confused about it because of the interface construct in OOP.
  3. Everything else.

I think more and more that programming is a bit like writing: there are many ways to do it, some are better than others, and it's more a question of personal preferences that we dare to admit. Typing is no exception.

There is no study which proves that "strong type safety" (which, in essence, doesn't really mean anything) improve the quality of our software. It's a safety net, but a basic one. With C++, many believed that the compiler would solve everything, till it became, indeed, a joke.

Here's what I think: history is repeating fast in our industry. We forget what was discovered already. It's a mistake, and I think we should sometimes look a bit more in the past than always lurking on the new tool, new ways, new trend.

Collapse
 
bytebodger profile image
Adam Nathaniel Davis • Edited

I think more and more that programming is a bit like writing: there are many ways to do it, some are better than others, and it's more a question of personal preferences that we dare to admit. Typing is no exception.

(Nodding along...)

I'm not "mad" that many people love TS. I'm not even particularly bothered by the fact that my employer is currently trending in this direction. But sometimes I wish that more devs/teams/companies would be honest about the fact that some architectural choices are made because they match their preferences.

If someone says, "A lot of our devs prefer TS and we've already made the choice to standardize on TS. Therefore, TS will be our default tool choice going forward." - You know what? I get that. I've got no problem with it. Those kinds of decisions get made every day in dev shops all over the world.

But it's a little annoying to me when someone tries to tell me that TS is empirically, measurably, demonstrably BETTER for the React frontend application I'm building that will depend upon a dozen different outside data sources. In those cases, TS isn't necessarily the best tool for the job. It's just... a tool. That could do the job. If you want it to.

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt • Edited

At least IDE integration, in case of TypeScript (and Kotlin), makes my development cycle faster, if even possible at all.

But sometimes strong-typed in Kotlin just hinder development... There are usually harder ways around, but that is no fun.

But I don't think it is ever proved to be better, though.

Collapse
 
somedood profile image
Basti Ortiz

Excellent points made. As much as I am a fan of TypeScript, I agree that TypeScript tends to make me feel too "safe" with my code.

The reason why type annotations are necessary is because we want to avoid "defensive programming", where we use a bunch of if checks just to sanitize and validate input. TypeScript removes this habit by giving us the illusion of type safety.

However, this type safety falls apart in user-facing "interfaces", where runtime data comes from the "outside". In this case, I wholly agree that TypeScript isn't a robust solution. Instead, defensive programming is perhaps more ideal, never mind the type annotations.

But in secure environments where the data has already been sanitized and validated (by means of defensive programming beforehand), I can say that this is where TypeScript really shines.

My main takeaway from this article is that TypeScript lives in a "perfect" world. It's an incredible tool for controlled internal environments. Otherwise, in user-facing runtimes, type "safety" is a dangerous habit that leads us to assume too much about the "outside" world.

Collapse
 
bytebodger profile image
Adam Nathaniel Davis

Great feedback!

As much as I am a fan of TypeScript, I agree that TypeScript tends to make me feel too "safe" with my code.

The key to being a great coder is to acknowledge that "too safe" feeling. It doesn't mean that TS is garbage. It doesn't mean that you should abandon it. It still has many points in its favor. As long as you're fully cognizant of that "too safe" tendency, you'll at least be more likely to guard against it.

we want to avoid "defensive programming", where we use a bunch of if checks just to sanitize and validate input.

Totally agree. That's why my next post will be outlining my approach to that problem, which, I believe, vastly simplifies the problems associated with defensive coding. (And endless if (... checks.)

But in secure environments where the data has already been sanitized and validated (by means of defensive programming beforehand), I can say that this is where TypeScript really shines.

Absolutely!

My main takeaway from this article is that TypeScript lives in a "perfect" world. It's an incredible tool for controlled internal environments. Otherwise, in user-facing runtimes, type "safety" is a dangerous habit that leads us to assume too much about the "outside" world.

That's precisely one of my main points. TS certainly has value. In some cases, it can be an amazing tool. But I'm seriously questioning its usefulness in purely frontend applications that rely on reams of "outside" data to fulfill their purpose.

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt • Edited
  • Type safety is opinionated, and TypeScript team choose not to emit runtime type checks.
    • I think Hegel is a tried alternative. I don't know how well it works, though.
  • You should always consider safety beyond types. Validating users' (or even devs') inputs are way beyond that (e.g. empty string "", and empty arrays [], are possible even in dev environment).
Collapse
 
somedood profile image
Basti Ortiz

Wow. Hegel looks very promising, but I'd imagine the build times to exponentially soar. I'd say this is an option worth considering particularly for the front-end (i.e. clients and front-facing APIs).

Thread Thread
 
patarapolw profile image
Pacharapol Withayasakpunt

You know that even tsc (or ts-node / ts-node-dev) can be slow to compile, right? Not as bad as Gradle, though.

Thread Thread
 
somedood profile image
Basti Ortiz • Edited

Yup, I believe I am too familiar with that reality. πŸ˜‚

I just figured that the additional runtime checks make compilation more computationally expensive, hence the longer build times than "just" TypeScript.

Collapse
 
bytebodger profile image
Adam Nathaniel Davis

Oh... that's cool. I hadn't even heard of Hegel before. I'm definitely going to look into that one.

Collapse
 
bradtaniguchi profile image
Brad

I'll always use TS for one reason and one reason only.

I am a lazy programmer.

I'm a lazy dev, and I wish JS+VSCode gave me better intellisense on the variables/interfaces I'm using, but it doesn't once you start including multiple files, or external data. When it does work, it actually is just using TS definitions under the hood anyways.

Its true TS isn't this a fool-proof safety-net that produces a false sense of security as its based on a "flawed" language model that can explode at any time during runtime due to my interfaces being wrong and me assuming the wrong stuff, and me being too lazy to check.

Id rather have a wonky interface than no interface. I don't know how many bugs I've created with my assumptions, and faulty pretenses, but I at least built something without split screening the docs, checking for typos every 5 seconds and building out a full test-suite of all edge cases for every function for full test coverage.

I'm sure the best of us will build the "perfect" kind of code that wont ever break because its been battle tested so it wont ever explode at run-time and can handle every and all errors perfectly, without using TS as a crutch. If your that kind of developer with that kind of resources, yes go ahead and make the jump.

I'm just a "lazy programmer" trying to make a deadline, and TS helps me get the job done faster with better intellisense, even if its "faulty" and makes my code "worse". Id rather have a faulty crutch than nothing.

Collapse
 
bytebodger profile image
Adam Nathaniel Davis

I completely appreciate these sentiments. And though it may not be clear from the content of my article - I completely agree with these sentiments.

Obviously, I've personally come to believe that TS is not my favorite tool. And for me, it seems to cause more headaches than it's worth. But that's all... for me.

If TS is the right tool for you, then... by all means, use it! If it's the right tool for your team, or your company, or for the particular project on which you're currently working, then... use it! One of the common themes that runs through many of my articles is: Don't become dogmatic about any particular tool. Instead, always strive to use the right tool for the job.

Also, I'm acutely aware of the fact that my experience with "plain ol" JavaScript has somewhat skewed my opinion on this. If I were just starting out in web dev today, I might genuinely prefer TS. Hell, I might even prefer it because I too can be an incredibly lazy programmer.

But I've been doing this shit for long enough now that most of TS's "benefits" feel lost on me. There are all these additional hoops to jump through to accomplish what I was already doing in vanilla JS. But I am not everyone. Everyone is not me. And I'll gladly admit that, for a great many people, TS might absolutely be the right tool for the job.

Thanks for taking the time to comment!!

Collapse
 
camerenisonfire profile image
Cameren Dolecheck

That was an excellent, thorough, and stylistic explanation. You're quickly becoming my favorite writer here on Dev.to.

My team is making a transition over to using TS. I think the biggest benefit has been less the hard assurances that things will work, because like you said they are not hard assurances much of the time, but the way TS helps us think of things in a different way. It can help slow down the coding process, in a positive manner. For reasons you said, I'm still not totally sold on the use of TS, but our last release at least felt better, partially because of TS.

Collapse
 
bytebodger profile image
Adam Nathaniel Davis

Thank you for the feedback!

I think you've hit on something good here. With TS, I've been looking for tangible benefits. But not all benefits are empirical. If the team is "all in" on TS, and if that commitment to its paradigms gives your team more confidence in their code and their deployments, then... what's not to like? Granted, that won't be enough for me to embrace it in, say, my personal projects. But that doesn't mean that it doesn't have real benefits for many devs/teams.

Collapse
 
jakkc profile image
Jakkc

Typescript devs thrive off gaslighting Javascript devs. Apparently you can't build web apps now unless you jump through a million unnecessary and arbitrary geeky typescript shaped hoops. It's stupid. I've been a professional for 8 years using exclusively JS. I have never ran into any of the problems Typescript fundamentalists claim we need to protect ourselves against. Perhaps JS became the most popular language in the world by virtue of it's dynamic typing system?

Collapse
 
bytebodger profile image
Adam Nathaniel Davis • Edited

I have long contended that dynamic typing isn't some bug to be washed out of the language. It's a feature.

Granted, if I were so inclined, I could spend some time making a solid case about why dynamic typing is evil. I could also make a solid case about why static typing is evil. In other words, both dynamic and static typing are neither good nor bad. They just... are.

I don't have any problem with dynamic typing languages or static typing languages. But I've never been a fan of choosing one - and then trying to make it into the other.

TS feels to me like someone said, "Oh, mannn... I really like this JS thing - but I gotta find a way to fix that darned dynamic typing!" I know a lot of people who wouldn't have any complaints about that scenario. But if I told them that I was working on a way to make C# dynamically typed, they'd look at me like I was an idiot.

Collapse
 
jakkc profile image
Jakkc

I completely agree with this. Today was my final straw with Typescript, I was working in a Vue TS app and writing a really basic action in a Vuex store. I wanted to reference the "rootState" parameter which is provided out of the box by Vuex. However I had to teach my compiler about this functionality in a third party library. This is the point where TS becomes complete and utter farce for me. I understand being wary of whats going in and out of your own functions, but if I have to teach the compiler how to handle a third party library then we have clearly strayed far away from the original selling point of TS. At this point it offers no tangible benefits whatsoever and becomes unnecessary overhead. Should I not trust my third party library to handle all its internals?

Collapse
 
blueharborbrandon profile image
BlueHarborBrandon

I see a lot of anti-TS arguments that amount to "it doesn't provide runtime guarantees". It's like suggesting that seatbelts are bad because they won't help if you get T-boned by a truck. The problem was not introduced the safety measures! The fact of the matter is that TypeScript moves some of the correctness-checking to compile-time instead of runtime. Maybe you wish it did more, but it is inarguably a step up from plain, untyped JavaScript. There are some mistakes that will be caught much faster with static types. If you don't see them, it's not because they're not there.

You might think it's a false sense of security, but that's user error. For external-facing code, if you're not confident that you'll get a value of a certain type, don't type it as such. Type it as any and then do your checks, which may allow TS to infer the proper types for the rest of the function. Or, next call a private/internal version that has explicit types.

So that just leaves the idea that it's too much effort for the benefit. That's primarily a matter of opinion... so I probably won't change your mind, but you'd have to do better if you cared to change my mind. (And if you don't care, why write a blog post and read/respond to its comments?) But let me back up my opinion with some ideas you might have overlooked:

  1. TypeScript can infer a lot. You could replace const createId = (length: number = 32): string => ... with const createId = (length = 32) => ... and it would understand the types just fine. Fortunately, this works well with the internal code you don't want to write types for.
  2. You said yourself that well-written apps are built of countless pieces. You also said types matter most at the interface. But if we connect those dots, we can conclude that the in-between makes up a significant part of the app! Combine that with #1: There's a lot of interface - where typing is agreed to be valuable - and a lot of internal code where typing takes little effort. Sounds like a win-win to me.
  3. You've looked at programming at rest, but what about change? If you learn that createId needs to take another parameter, anything that uses it needs to change, too. TypeScript will not let you forget to update the consuming code. Or, if you decide to start using numerical Ids, things might just cascade through type inference. But, if anything relies on that id being a string, TypeScript will let you know. TypeScript requires more work in the places where things can go wrong.
  4. There's an incredible amount of expressiveness in the type system, especially when complex structures are involved. It goes way beyond primitives, classes, and interfaces. I'd highly recommend browsing the advanced features TS offers. A favorite of mine is "Discriminated Unions".
Collapse
 
mikel profile image
Michael Lawson

While I think this article is extremely well written, and I do appreciate it, your comment does lay out some excellent points. First and foremost is that regardless of JS or TS you can still have runtime errors. If you get too complacent in your TS code because you think the compiler got everything, then that's on you and not the language, as is the case in any environment.

Collapse
 
ecyrbe profile image
ecyrbe • Edited

Hi Adam,

I know you wrote this article some time ago now, i just wanted to share with you what i use typescript for.

First i completely agree, typescript is not the answer to all runtime issues we face when using javascript.

Like you said it can make you too confortable about your code if you don't ckeck your external data, and then when feeding it live with bad data all this comfortable dream goes away!

But like a lot of programmers, i'm lazy, i don't want to do defensive programming in all my code. So what i do is :

  • use typescript as code completion utility.
  • use typescript to make type checking sound asuming i'm feeding correct data to my program.
  • use data validation from any external data input to not make this typescript dream go away (i use ajv or hapi joi to validate everything) :
    • user data (forms) validation
    • data transfert objects (dto) validations
    • api result data validation
    • localstorage validation
    • database data validation (when using mongo)
    • cache validation
    • config file validation
  • ban any type, prefer generics and when generics don't apply use unknown or Record<string,unknown> or unknown[].

All this comes at a cost that not everybody wants to pay. But for me and my team it works. We are now using typescript for 2 years and we are now really efficient with it and this workflow.

Collapse
 
bytebodger profile image
Adam Nathaniel Davis • Edited

First, a sincere "Thanks!" for the feedback. It's appreciated. And, for the most part, I think I actually agree with everything you've written here.

I've been "slinging code" long enough now that I can (usually) assess, fairly quickly, the relative strengths-and-weaknesses of any given approach. Specifically, with regard to TS, I definitely don't disagree with the benefits you've outlined here.

In fact, another senior member of our team spoke up a month-or-so ago and said, "Guys... why are we going down the TS path???" And when he did, I pointed out code-completion as a major benefit. I use JetBrains/WebStorm, and I find their code-completion to be awesome - even for non-TS projects. But I will freely admit that the code completion is even better when I use it for TS projects.

That being said, part of my inspiration for writing this article was that, in the final analysis, I just didn't find these "benefits" to be worth the cost. To be absolutely crystal clear, I'm NOT saying that the benefits aren't there. And I'm not asking, at all, for you or anyone else to agree with my analysis. But for me, the benefit... just, isn't, there.

I will also outline one last point here: I've come to accept the fact that, a lot of TS's supposed-benefits are probably things that I've kinda figured out how to "fix" in my own vanilla-JS dev. And I'll freely admit that, in most teams, you can't assume that most of your devs are senior enough to have figured out those things on their own. So... on "most" teams, maybe TS is a far better option. I can freely acknowledge this. But for me.... it just feels like an unnecessary burden.

But... that's just a lotta opinion from me...

Collapse
 
tshddx profile image
Thomas Shaddox

I hear complaints about the lack of runtime type-checking very often, but I still don't quite understand the complaints.

In your example of createId, how is it being called at runtime with something other than a number? Surely that's only possible if you have some JS (non-TS) code that's calling createId, right?

If you're using window.prompt, for example, its return type is string | null, and if you're passing that to parseInt the return type is number and it will always return a number. You're doing a runtime check for isNaN, but that has nothing to do with types, because typeof NaN === 'number'.

That's just a runtime check for specific numerical values, no different than, say, checking length < 0. We can't expect a type system to handle those checks for us at compile time, unless we're using a language with something like dependent types (those are mostly research languages and interactive theorem provers).

Collapse
 
itsjzt profile image
Saurabh Sharma

Agreed, adopting graphql can benefit the companies because its a type safety but at the interface level