Ask HN: Is it worth it to invest in learning TypeScript?
I don't do much frontend programming so I've been mainly using Javascript. However, more and more libraries are using Typescript which makes me think that I should make the jump. But I don't understand how adding types will suddenly make frontend coding more efficient. I tried researching for pros and cons but nothing came up.
98 comments
[ 3.2 ms ] story [ 218 ms ] threadThat said, I stick with JS and I'm perfectly happy doing so.
Classes are still useful, of course, as encapsulations of state, but I don't remember the last time I wrote something polymorphic in TypeScript that didn't feel faintly wrong. Coming from a Java/C# background, the "easy path" in TypeScript feels to me like it nudges you more towards compositional architecture (which is a good thing!).
Understanding TypeScript in depth is not as easy. It's a language with many features (some of which were not designed to make the language great, but to be able to cover the quirks of JavaScript), and a sophisticated type system.
Sophisticated type systems always take some time to really understand. TypeScript's has various features you don't find in many modernish OOP languages, such as structural typing, control flow based type analysis (like Rust), and reasonably sophisticated generics.
I use Haskell professionally for almost 10 years (including teaching it as consultant and contributing to GHC), and am quite familiar with many OOP languages, so I guess I have a reasonable background for "learning" TypeScript. I use it regularly, but I'm certainly still "learning" it for a while now.
TypeScript's error messages can be huge, and tougher to understand than nominal-typing systems, as you need to get used to diving into the structures of types instead of being told that type Dog isn't type Camel.
Another challenge is that there are multiple ways to achieve a type-related goal in TypeScript, and it isn't always obvious which one you should go for. One such example that a friend brought up yesterday is when to use unions vs enums [1]. As you can probably tell from that post, even diving into this topic alone can take an afternoon, and the answer will also change over time as TypeScript improves and adds features. To me, having properly "learned" a language implies knowing those things, as your decisions will make it into the APIs that you and others will use longer-time.
So my point is that TypeScript is far from trivial.
But it doesn't have to! Spending a couple months to learn something well is a great investment if it makes you more productive for years.
TypeScript is a great improvement over JavaScript, and I'd recommend anyone using JavaScript to learn and use it.
[1]: https://stackoverflow.com/questions/40275832/typescript-has-...
You're confusing runtime checks with compile time checks. If you mess types while developing, you will know instantly with TypeScript but you'll find out during testing with JavaScript (or in production)
The incompatible changes are more likely caught at compile time, and far less likely to become apparent only when deployed.
That said, also TS itself is not fool proof - there are times where the config in use (strict vs. non strict null checks) and other factors (e.g. de-serialising JSON) can mean that your data does not in fact match the expected types.
I don't agree. 99% of javascript/typescript programs will be dealing with data that is potentially null and without strict compile time type checking that typescript affords writing correct javascript programs is almost impossible.
It's tedious but it's far from impossible.
Validating perfectly at run time is exceedingly difficult and tedious. Does anyone actually write defensive code like this?:
By contrast, the TypeScript code is reasonable: > it does make the code more terseNo, TypeScript code with explicit type annotations is less terse than the typical unsafe JavaScript code that lacks type checks.
> It requires that you define types for every little thing
No, the TypeScript compiler has type inference. It can assign types based on how values are passed between known functions. While it's a good idea to explicitly type all function signatures in TypeScript, it's not mandatory unlike Rust.
Setting the type of unknown data to `unknown` forces you to validate it.
Is it worth learning it? I'm sure type-less job offers will continue to exists in large numbers, so if you don't like it then don't study it.
Note: TS is generally not referred to as "testing", this is just my simplification. I've been using TS for years for everything and it has avoided a lot of bugs — which is something I notice when porting projects to TS.
Once you've worked in a codebase with consistent TS usage, it's very, very painful to go back to vanilla JS, so imo yes, TS is worth the investment.
The things you’ll get: 1. It’s going to force you to think more about how you structure your program. You’ll probably end up with a cleaner design. 2. It’s going to make you code faster because of the awesome autocomplete functionality you get out of the box (at least with VSCode). 3. It’s going to give you much more confidence that your code won’t break at runtime. There’s still a chance it will (write unit tests), but it’ll be much less frequent. 4. Types are a kind of documentation, so your future self will thank you.
I wrote a post a couple years ago describing my journey learning and using TS, with a set of takeaways at the end:
https://blog.isquaredsoftware.com/2019/11/blogged-answers-le...
I said then that "I refuse to write any more app code that isn't TS", and that's even more true today.
TS is not perfect. It does add overhead. But, it adds a huge amount of value and safety to your app. The goal is to use it pragmatically, such that Value > Overhead.
*edit*
I'll add a bit of additional context here based on my experiences since then.
Typing application code is usually relatively straightforward. I'll use React and Redux as an example, because that's A) what I use at work, and B) I maintain Redux.
Per our Redux TS Quick Start page [0], you'd start with a few lines to infer the TS types of `RootState` and `AppDispatch` from the store, and create pre-typed React-Redux hooks (which are _much_ easier to type than the legacy `connect` API) to save from repeating those types in components. For each slice reducer, you'd add a TS type for the slice's state, and declare the type of each action's contents as `action: PayloadAction<string>`, etc. For React components, add a type declaration for the props of each component, and add types to function arguments as necessary (change handlers, etc). The React TypeScript CheatSheet [1] is a fantastic resource for learning how to use TS + React together. Also be sure to type any data coming into the system, such as API responses, and any other "business logic" you might have.
Those should get you 80%-ish types coverage without too much effort, and all you really need to know is how to declare types for objects+primitives, and a few bits from the React and Redux lib types.
I also strongly disagree with many of the "recommended" TS-related linting rules, like "always declare a return type for every function". It's not _wrong_ to have those, but in my experience TS works best when you can let the compiler infer as much as possible.
I still firmly believe that for _app_ development, it's not worth spending hours and hours arguing with the compiler to come up with a "perfect 100% correct" type definition for more complicated scenarios. If you know that a function takes `TypeA` as an input and returns a `TypeB`, but there's really complex transformations inside and it's really hard to convince the compiler what you're doing is correct, feel free to do whatever `as` casting or `// @ts-ignore` you need to in the middle.
Library types, on the other hand, are the opposite case. Library APIs are often highly generic in both the "use case" and "TS types" senses. There, it _is_ worth spending the time to come up with very complex typedefs with tons of generics and conditional types, because those are often needed to make the _end user experience_ a lot easier. Try looking at the types for Redux Toolkit, React-Redux, or Reselect [2] [3] [4] - our types are complex, so _your_ code doesn't have to be.
I spent a ton of time just yesterday trying to make improvements to the Reselect types, because as a maintainer I want our users to have a good experience. But for you as an app dev, it should be a lot simpler. The payoff is that you get all the nice benefits of TS: static detection of common errors like typos and mismatched fields, documentation of your data structures, intellisense, confidence in refactoring, less need to write repetitive "is this argument the right type?" logic, and much more.
[0] https://redux.js.org/tutorials/typescript-quick-start
[1] ...
As a greyhair I've seen many languages come and go. I don't want to sound pessimistic but the idea of trading one set of problems for another isn't novel.
I am of the opinion that all roads ultimately lead back to the fundamentals.
(With one nit: TypeScript enums are weird and while they work in JavaScript ways they are weird and might be best off being rethought, even if it's backwards-incompatible.)
Static typing obviates most runtime type checking, which your module boundaries need to be doing (and exercising in tests). Libraries like runtypes deal with the last mile of it by generating runtime type guards that also project back into the static type system. This removes the need for entire classes of tests, as well as many of those handling intra-module transforms. It's telling that the people doing some of the best work in, say, Ruby are in on both tooling like Sorbet and libraries like dry-types/dry-struct -- because the benefits are significant in terms of minimizing engineering risk.
Static typing is also standardized and machine-readable documentation. This can't be understated. Human-written documentation rots with changes. The guarantees at module level from your static types does not.
Particularly when gradually introduced, these are significant force multipliers. If you want to take on the additional risk for your toy projects, more power to you (I sometimes write Ruby when doing something that doesn't matter) but I certainly find those benefits significantly more than "marginal" if anyone else ever has to deal with my code--including future-me.
I've heard this argument many times but it's misleading. Well written functional tests will be able to identify type mismatches implicitly. For example if you add 10 + "1", you will get "101" - The test will fail. You don't need to check if the result is a string, you just need the assertion to expect the number 11. Tests will catch type mismatches implicitly. In practice, this applies to pretty much every kind of type mismatch. Type mismatches break functionality; so if the functionality is well tested, then type mismatches will be caught implicitly.
Do you have any large typescript projects?
What do you see them moving to?
> Update June 10 2020: I saw that this design doc was being discussed more widely. Most people don't have the context to understand this narrow technical document - it is only applicable to a very particular, very technical situation in the internals of Deno. This is not at all a reflection on the usefulness of TypeScript in general. It's not a discussion about any publicly visible interface in Deno. Deno, of course, will support TypeScript forever. A website or server written in TypeScript is a very very different type of program than Deno - maybe much more so than novice programmers can appreciate - little of Deno is written in TypeScript. The target audience is the 5 to 10 people who work on this particular internal system. Please don't draw any broader conclusions.
> The cutting edge JS ppl are moving away from TS right now, at least some of the ones I follow on twitter seem to be over it.
Who are these people, why are they moving away from it?
> OP might be on to something, not wanting to waste time chasing trend n-1
If you need static typing for JS now, TS is your best bet. You can also wait N years for TC-39 to add it but so far nothing has been proposed.
I know the rules of JavaScript, including all the weird type coercion stuff, undefined, etc. I know how to write correct programs, but I hate the human effort of having to jump around my codebase to recheck definitions and to double- and triple-check my work for silly mistakes.
Writing TypeScript code makes me do a bit more work upfront to annotate types. But in exchange, the compiler helps me tremendously in tediously checking all the types and names. Functions with types are more self-documenting than untyped functions; it's easier to read and figure out what a function does at a glance.
In a sense, compile-time type-checking is more powerful than unit tests because unit tests only cover functions and branches and (run-time) types that are actively taken, whereas type checking applies to all code all the time.
Before discovering TypeScript, I used this workaround a few times: For complicated pure algorithm / data structure stuff (not DOM or user interface stuff), I would prototype the program in Java with all the glorious types, test the heck out of it, and then translate it line by line to JavaScript.
I was hesitant at first too, but I am sold on it now. Most libraries provide types too, so the entire JS ecosystem has basically adopted it as well.
The ECMAScript spec will probably supersede TypeScript in the near future anyway. This has happened historically with other dead Javascript dialects (example: when classes were included in ES6).
The alternative is finding out some time later (possibly in production) that your function that had always been assuming the arguments were non-null strings suddenly generates an error when it gets passed in null or a number or object or similar.
TypeScript is a huge productivity boost for JavaScript programmers (and similarly mypy for Python). There's no way I'd be happy working with either language without these tools. TypeScript is also useful on the backend, if you're using Node.
TypeScript makes your interfaces and their documentation much more explicit than with vanilla JS. If you work on your code in a team, you actually want to very clearly document the inputs and outputs of your functions and the types of your data structures. Doing this with JSDocs is cumbersome and error prone in my experience and actually more work than just using TypeScript.
Having explicit types with TypeScript helps both machines (better / safer refactoring) and the humans to reason about the code.
So the bit of extra effort to add the types is very well invested. And keep in mind that developers spend much more time reading code than writing it.
That's all it is, and it works.
* If you don't know a typed language - learn one. TS is probably the easiest place to start.
* If you know a typed language, TS is just going to be a different flavor of that.
TS offers a better developer experience (better code completion in your IDE), types help document your code and refactoring will be less painful. Also you gain some level of type safety (though less than languages with a sound type system).
Drawbacks are slow compile times and cryptic error messages and general having a additional tool that adds complexity. Also the level of type safety is dependent on how disciplined you are (though some linting rules might help).
There are languages with much better type systems and faster compile times that transpile to JS that might also be worth noting like Elm, ReScript, Purescript and so on but TS has of course the best migration story with the "just JS but with types" promise.
So generally, yes learn it, use it.
1. It does not replace type checks at runtime (in integration layers)
2. Compilation and startup (in backend land) is slow
3. Some tooling seemingly caches (webpack? ts-node?), we regularly run into situations where rebuilding locally works but then building for prod fails with type errors
2. Yes and no. It's not the fastest build out there but if you've enabled incremental builds it's quite quick unless you're touching heavily related-to code (libraries that are imported all over the place). If that's not fast enough for you, I've seen people having very good success with `swc`.
3. I can't speak to webpack, but ts-node shouldn't be caching anything last I looked at it.
The smaller your project, the more pointless typescript will feel. Working alone on a small project, it’s a LOT of extra stuff on the screen to avoid a very specific kind of bug.
And it takes 5 minutes to set up.
Once you're proficient in TS, adding type annotations really doesn't take much time, and it helps save time testing by letting the compiler "test" your code before it even runs.
Whereas how this will behave:
is far easier to keep in your head. Multiply that effect by 100k lines and the TypeScript program becomes a lot more fun to build on because you get to spend less time thinking about edge cases.