I'm not against TypeScript, but I don't really see the massive advantage. I rarely see problems that are due to typing, and the downside is usually limited as I keep my JS on the frontend, not the backend. Regular JS/ES6 just flows better.
This is a fallacy similar to the Blub paradox: if your language has a weak[1] type system, then it isn't capable of recognizing many problems as "type error". But stronger type systems can express stronger invariants. So something that isn't a type error in one language will be a type error in another. This changes how the programmer conceives of problems.
Example: missing a case in a switch statement isn't a "type error" in C or Java, but it is a "type error" in languages like Rust or ML, because they have sum types with exhaustiveness checking. Other examples: array bounds checks can be eliminated with dependent types; lifecycle bugs like use-after-free and double-free can be eliminated with substructural types.
[1] "weak" in an informal sense of "not very expressive"
Correct me if I'm wrong, but doesn't the Blub Paradox imply that languages dedicated to Code Golfing are at the pinnacle of expressiveness, and look down on everyone else's languages (for their extreme verbosity, compared to the golfing languages)?
Yeah or even simple typos, or mixing up the order of arguments, are things that are hard to catch in regular JS (except at runtime) but trivial in TS.
I suspect a lot of people might have had bad experiences with codebases which overuse complex types or trying to type things like Redux which is messy. When I use TS for personal stuff I’ll typically be a bit loose about things like any in places where I don’t care (for now) and I feel it doesn’t add much overhead, but I have been using it for a long time so it’s become second nature.
This is a very fair comment, and you seem open to understanding why types are useful.
"problems that are due to typing" is a very difficult thing to unpack because types can mean _so_ many things.
Static types are absolutely useless (and, really, a net negative) if you're not using them well.
Types don't help if you don't spend the time modeling with the type system. You can use the type system to your advantage to prevent invalid states from being represented _at all_.
As an example, consider a music player that keeps track of the current song and the current position in the song.
In the example above you _are_ using types. It might not be obvious that some of these issues can be solved with stronger types, that is, you might say that "You rarely see problems that are due to typing".
You'll notice that this kind of safety is pretty limited. If you're going to write a music app, you'll probably need API calls, local storage, URL routes, etc.
TypeScript's typechecking ends at the "boundaries" of the type system, e.g. it cannot automatically typecheck your fetch or localStorage calls return the correct types. If you're casting, you're bypassing the type systems and making it worthless. Runtime type checking libraries like Zod [0] can take care of this for you and are able to typecheck at the boundaries of your app so that the type system can work _extremely_ well.
[0]: https://zod.dev/ note: I mentioned Zod because I like it. There are _many_ similar libraries.
Do you ever see null or undefined access errors? As a TypeScript developer I haven’t seen one for many years.
Also, when you have types it changes how you code itself. When I change a schema or refactor some function, I don’t need to think at all to make sure I’ve updated all the code that depended on the old schema or API; just fire the TypeScript compiler and it tells me everything that needs to be updated.
I’ve also not seen any issues for a long while where I’ve missed some conditional case, because I use discriminated unions with switch statements more, something that looks weird in normal JS but is very useful with types, since it tells me if I missed a case automatically.
Add that I’m managing a team of engineers, and so I can easily make sure they’re also not missing cases either, by setting the convention and having them see the light.
Putting aside other things like for instance always knowing that we’ve validated inputs for API endpoints since unvalidated inputs are the unknown type and therefore effectively unusable; or always knowing we’ve parsed and serialized dates correctly since we use branded string types to distinguish them from any other string with 0 runtime impact; the list goes on.
So yeah, it might just be the case that you haven’t actually internalized what coding with types even means, so you’re unable to imagine how it can help you.