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...
For further actions, you may consider blocking this person and/or reporting abuse
Thanks for writing this.
Awesome article
You're welcome! I'm glad you enjoyed it!
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.
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.
(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.
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.
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.
Great feedback!
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.
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.)Absolutely!
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.
""
, and empty arrays[]
, are possible even in dev environment).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).
You know that even
tsc
(orts-node
/ts-node-dev
) can be slow to compile, right? Not as bad as Gradle, though.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.
Oh... that's cool. I hadn't even heard of Hegel before. I'm definitely going to look into that one.
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.
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!!
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.
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.
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?
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.
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?
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:
const createId = (length: number = 32): string => ...
withconst 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.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.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.
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 :
sound
asuming i'm feeding correct data to my program.any
type, prefer generics and when generics don't apply useunknown
orRecord<string,unknown>
orunknown[]
.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.
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...
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 callingcreateId
, right?If you're using
window.prompt
, for example, its return type isstring | null
, and if you're passing that toparseInt
the return type isnumber
and it will always return a number. You're doing a runtime check forisNaN
, but that has nothing to do with types, becausetypeof 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).Agreed, adopting graphql can benefit the companies because its a type safety but at the interface level