I recently switched back to JS for a prototype of a programming language.
I immediately felt more productive.
At times, the TS systems feels like a theorem prover. Until it doesn't. And then you're left with a bunch of types that almost do what you want... but not quite; Always tempted to experiment again for a day or two.
But let's see what happens down the road. Maybe I'll miss the incidental documentation the typings provide.
With TS its like you’re writing the unit test and your code at the same time, and if your types are expressed well enough you can also skip the compile+run+verify step.
I’ve had cases where I would spend days just writing code, refactoring and iterating, without building the project once, compile it at the end, and have a complex feature work correctly on first try, passing all the functional tests.
It’s like I have a pair working with me constantly compiling my code and pointing out syntax and interface errors while I concentrate on the business logic and big picture stuff.
When I go back to JS it’s as if I now have to do all that manual labour too, as well as constantly write and run unit tests myself to make sure what I write actually works.
Though it definitely took some time to get this comfortable with the TS type system.
It took some getting used to because things end up a bit less obvious, but I found that with the IDE's syntax highlighting capabilities, actually inspecting the inferred types isn't as much of an issue. And then you spend less time typing out type names.
Always tempted to experiment again for a day or two.
Maybe that's it. I've never felt bad about settling for 95% of the benefits of static typing and slapping any/unknown on the edge cases.
Part of good language design is attempting to minimize bad programming habits. In this case, a language with a HM type system would avoid the issue all together, while affording the same productivity gains from having static types.
The places where the type system encourage rabbit holing are almost always where bad types/APIs are already prevalent. Where you’re starting at the type level and don’t have an inclination to allow all manner of dynamic nonsense it’s not that different from types in an ML-family language.
In code consuming types I relie on inference 80% of the time, sometimes I need to specify generics, if it fails I do dirty casts, if that fails I do dynamic blocks.
Thankfully, the impulse to waste time trying to come up with the most precise typing possible for everything hasn't been as strong with TypeScript as it used to be with Haskell for me. In part that's because TS's type system is so ridiculously expressive that I can say what I want to say without spending too long on it anyway, in part it's because the system's proud unsoundness and the ability for typings to simply be wrong means that I know not to stake my life on the types anyway. Besides, in my experience, the more precise I try to make the types at an interface, the more I need to cast in the internals. Better to find a balance that keeps both reasonable.
Isn't that exactly why you use types to begin with?
https://blog.isquaredsoftware.com/2019/11/blogged-answers-le...
I also try not to let any escape function boundaries.
Recast it to something better when returning something.
No it doesn’t. You’re casting to `any` and hiding that fact. Both top types can be anything at all, `unknown` is only safer if you narrow it to something else by testing it. If you cast it to something else you’re just treating `unknown` as `any`.
But yeah, sometimes you hit a wall and need to do something unsafe.
If we couldn't do something 100% type-safe then we weren't supposed to do it at all. I kid you not.
I got off of that project as soon as I could manage without burning a bridge. Funny thing was that before that? I thought I was quite the stickler for getting types as correct as possible. Turns out I was off by an order of magnitude of what a real "stickler" for correct types could be...
The only downside of burning bridge is that now, I don't have an overview on how bad shape this project is.
Probably just means you are smart and good at testing at some level ;-)
For me the biggest benefit of TypeScript is probably when I debug or extend other peoples code (i.e. all the time) and I don't have to hunt down calling functions to see what gets passed in.
I mostly work on large projects written by other people over the course of years and often this simple thing can save me several minutes several times a day.
I found it far more productive that going through rabbit hole of TS and its compiler. I write my `definitions.d.ts` for my objects, and use them simply
/** @type {ns.MyType} identifier */
const identifier...
and voila, my IDE gives me auto-completes and warns me when I'm doing silly stuff.It works for functions as well using
/** @param {type} parameter name */
and is generally a good idea to use.It gets you 80% of the way there with no compiler/transpiler (although one might argue that the IDE is compiling non-stop on file saves, with its language server).
I embraced Typescript when it was new and the Javascript standard was a total mess. It was leaps and bounds ahead and closer to something like AS3. At the time TS was godsend.
Today, JS + webpack gets you really far using the latest ECMAscript standards.
Same with IDE. The amount of stuff my IDE can deduct based on my few typings and my use of modern strict javascript has strongly reduced the need for another transpiler (on top of webpack).
I found jsDoc to be a perfect 80-20 solution.
Because at the end of the day, TS isn't a compiler, it's a transpiler. You're not compiling to bytecode in a vm, you're still in javascript.
This saves my bacon in the front-end. For the back-end, I most definitely choose a strongly typed language like Go.
My team was really happy with the result, but I'm afraid that if layoffs happen, I'll be on the shortlist.
But someone calling themselves startup-cto.net should be a lot more pragmatic about the value of strong types and willing to embrace the possibility of change!
Writing types give me more pleasure than it should... but if something is hard to type and unlikely to be referenced outside the local scope, it often isn't worth the effort.