But, two things have happened. My once sharp-as-a-japenese-knife memory feels a bit more like safety scissors nowadays, and the type system has added such fantastic support for useful features - unions, enums and the lot keep getting better with every release. Generics, mapped types and advanced types get really close to being able to fully describe the full expressive power of JavaScript. I dove in head first a few years back, and have only a few small quibbles over what it can and cannot express, or how easy it is to do so.
With all of that said, it can be really hard to sell JS veterans on TS. Intellisense in webstorm and the like can be quite powerful, especially if they drank the JSDoc kool-aid, so it can be tough to really clearly spell out the advantages since their tooling mimics a type system already.
As someone who is not sold on TS and writes JS every day, what advantages does TS provide over JSDoc? Both are just valid during compile/build/transpile time, so they seem mostly the same, except one is built and pushed by a huge company that has a history of supressing open source, while the other one is built by the community for the community.
I like that you get something like documentation as a computed property of your object based on what it has moved through over time. I like that I can feed an object to a generic function and see what it’s shape is when it comes out, all without actually running the object through the function or looking at the functions documentation. That sort of thing.
I’m guessing from your comment that JSDoc can do things like prevent you from shipping if you try to feed a function an object that is incompatible with the function signature. TS can also stop you if it might be incompatible, which results in creating a provable system.
Edit: you can also use typescript (the compiler) with JSDoc annotations instead of typescript (the syntax). It occurs to me that this might have been what you meant. If so, and you’re writing typescript conforming JSDoc, then I think the only difference is (mostly) just a philosophic one. Do you write ts syntax and this “force” the code to be compiled/checked before it can run (except not really because lots of people are separating compile and build these days), or do you note that it’s going to end up as js anyway and so just write js that you can use with the ts compiler.
If you’re in the second camp, then I guess the benefits would be:
- built type defs that you can share with consumers of your code…perhaps you can build these even with JSDoc?
- early adoption of ECMAScript features, if you’re into that sort of thing, without needing to worry about if it’s supported on all your targets yet (ie, like Babel)
That simply isn't an option with Typescript- it wont compile if there are internal errors, so your only real concern is ensuring API responses and the like are what you expect them to be.
Additionally, unless the tooling and spec has changed substantially since I last used it, JSDoc is awkward at best at expressing anything other than simple types. You can pretty drastically reduce the menial effort in some cases with advanced, mapped and generic types. For example, if you have some object of type Thing, and you need to represent an object with all of the same fields as being optional (say for a PATCH endpoint), it is simple as using the type `Partial<Thing>`. No worry that the two types will ever get out of sync with each other.
Another example is that you get control flow analysis- more than simply detecting unreachable code from return blocks, there are a few ways the tooling knows that a type is refined. If you have an optional parameter to a function and an if statement that checks it is set, within the if statement TS knows that it exists, but outside will warn you that it might not.
The editor tooling, and also the tooling tooling. Working with type-checked, autocompleted queries in Prisma and Hasura has been wonderful (yeah, I know C# has had LINQ forever - I also remember how awesome LINQ was when it came out!)
I used this recently for a project that couldn't use typescript.
It's a tradeoff: less use cases (garbage collection rules out some stuff), smaller ecosystem (albeit one can use ruby code as-is or with little modifications), concurrency-but-no-official-parallelism. The benefits: drastically higher expressiveness, terseness and big stdlib.
From idea to production, given good knowledge in either tech: Crystal is way faster to ship things. Only after many months/years into the project and multiple teams involved Rust might catch up.... but this is not the scenario PG speaks of, right?
... or maybe I am just an old Ruby fart and Crystal matches the way I think perfectly.
Lets be honest- this is probably like 90% of the reason that people make the switch.