> The fact that there can be runtime type errors that were proven impossible at compile time is why I will never enjoy TypeScript.
The "impossibility" is just a trait of the type definitions and assertions that developers specify. You don't need to use TypeScript to understand that impossibilities written in by developers can and often are very possible.
My first introduction to TypeScript was trying to use it to solve Advent of Code.
I wrote some code that iterated over lines in a file or something and passed them to a function that took an argument with a numeric type.
I thought this would be a great test to show the benefits of TypeScript over plain JavaScript: either it would fail to compile, or the strings would become numbers.
What actually happened was it compiled perfectly fine, but the "numeric" input to my function contained a string!
I found that to be a gross violation of trust and have never recovered from it.
> I thought this would be a great test to show the benefits of TypeScript over plain JavaScript: either it would fail to compile, or the strings would become numbers.
You're just stressing that you had a fundamental misunderstanding of the language you were using when you first started to use it. This is not a problem with the language. You simply did not understood what you were doing.
For starters, TypeScript does not change the code you write, it only helps you attach type information to the code you write. The type information you add is there to help the IDE flag potential issues with your code. That's it.
See how node introduced support for running TypeScript code: it strips out type info, and runs the resulting JavaScript code. That's it.
If your code was failing to tell you that you were passing strings where you expected numbers, that was a bug in your code. It's a logic error, and a type definition error.
Static code analysis doesn't change the way you write code. That's your responsibility. Static code analysis adds visibility to the problems you're creating for yourself.
No tool is perfect. What matters is if a tool is useful. I've found TypeScript to be incredibly useful. Is it possible to construct code that leads to runtime type errors? Yes. Does it go a long way towards reducing runtime type errors? Also yes.
> No tool is perfect. What matters is if a tool is useful
Some tools are more perfect and more useful than others.
Typescript's type system is very powerful, but without strict compile-time enforcement you still spend a lot of effort on validating runtime weirdness (that the compiler ought to be able to enforce).
Yes that's true, but there's effort to consider on both sides of design decisions like those TypeScript has made. Much of the compile time behaviour comes from the decision for TypeScript to be incremental on top of JavaScript. That allows you to start getting the benefit of TS without the effort of having to rewrite your entire codebase, for example. Having used TS for many years now I feel that the balance it strikes is incredibly productive. Maybe for other folks/projects the tradeoff is different - but for me I would hate going back to plain JS, and there's no alternative available with such tight integration with the rest of the web ecosystem.
Have you seen ReScript? Of course it is not as popular as typescript but it improves on all the bad parts of typescript. You'll get sound types with the pain points of javascript stripped out. Because it compiles to readable javascript you are still in the npm ecosystem.
You don't have to rewrite your whole codebase to start using it. It grows horizontally (you add typed files along the way) compared to typescript which grows vertically (you enable it with Any types).
The point is that we don't have to move back to plain js. We have learned a lot since typescript was created and I think the time has come to slowly move to a better language (and ReScript feels the most like Javascript in that regard).
> Typescript's type system is very powerful, but without strict compile-time enforcement you still spend a lot of effort on validating runtime weirdness (that the compiler ought to be able to enforce).
That's something that you own and control, though. Just because TypeScript allows developers to gently onboard static type checking by disabling or watering down checks, that does not mean TypeScipt is the reason you spend time validating your own bugs.
> Just because TypeScript allows developers... does not mean TypeScipt is the reason you spend time validating your own bugs
Unfortunately, taking an ecosystem-wide view, it means exactly that. If one of my dependencies hasn't provided type stubs, or has provided stubs, but then violated their own type signatures in some way, I'm on the hook for the outputs not matching the type annotations.
In a strict language, The compiler would assert that the dependency's declared types matched their code, and I'd only be on the hook for type violations in my own code.
The "impossibility" is just a trait of the type definitions and assertions that developers specify. You don't need to use TypeScript to understand that impossibilities written in by developers can and often are very possible.