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.
I'm interested to hear folks prediction on the future of the language.
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.
If we're wild-assed guessing, mine is that TypeScript eventually merges with JavaScript. It is a wisely designed set of optional type constraints that aren't incompatible with JS proper. Seeing as how every conformant TypeScript compiler is also a conformant JavaScript compilers, the split is pretty small and eating one's vegetables is good for you.
(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.)
If TypeScript becomes natively interpreted (instead of transpiled), I might actually consider using it for my personal projects. In the meantime, I don't use it because I cannot stand the build, bundling step and the problematic debugging experience with source mapping (and difficulty to debug production errors where source maps are not available). If you write code correctly with loose coupling and good tests, static typing only provides marginal benefits.
Your last sentence is writing a very large check that I'm not confident at all you can cash.
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.
> Static typing obviates most runtime type checking, which your module boundaries need to be doing
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.
I personally hate everything about the transpilation step; the time it takes (slows down dev-test iteration by a lot), the source mapping aspect, debugging in a live production environment (I hate having to debug transpiled/mangled JavaScript). I hate having to handle multiple permutations of engine versions (too many possible permutations of tsc and node.js version numbers which introduces configuration and setup difficulties; it rarely works out of the box; it's a nightmare for open source projects when you're potentially dealing with a broad range of different operating systems and environments which you have 0 control over; maybe the user needs tsc version x.x.x for some different reason and you cannot force version y.y.y onto them!!! So their tsc version will not work with your tsconfig)... It just adds a ton of bloat, dependencies (security/maintenance burden), setup/compatibility problems and the value it adds is marginal.
I think Typescript is here to stay, way more than Coffeescript was. On the other hand, I wonder if there's not a missed opportunity by compiling TS to JS. You lose all the type information that could be used to optimize the code.
How so? Coffeescript was mostly absorbed by JS, a true success story. 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. OP might be on to something, not wanting to waste time chasing trend n-1
It seems to me that there is a divide of angular typescript apps that are about 3-5 years old and a new wave of react flow apps. Wonder what the stats are.
This is just a Deno-specific internal thing due to tsc being too slow for their specific case. Deno itself can read and execute TS code and they aren't planning on dropping that.
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.
Comments
Yes, absolutely, 100%.
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] https://react-typescript-cheatsheet.netlify.app/
[2] https://github.com/reduxjs/redux-toolkit/blob/v1.6.2/package...
[3] https://github.com/reduxjs/react-redux/blob/v8.0.0-alpha.1/s...
[4] https://github.com/reduxjs/reselect/blob/v4.1.2/src/index.ts...
I'm interested to hear folks prediction on the future of the language.
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.
If we're wild-assed guessing, mine is that TypeScript eventually merges with JavaScript. It is a wisely designed set of optional type constraints that aren't incompatible with JS proper. Seeing as how every conformant TypeScript compiler is also a conformant JavaScript compilers, the split is pretty small and eating one's vegetables is good for you.
(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.)
If TypeScript becomes natively interpreted (instead of transpiled), I might actually consider using it for my personal projects. In the meantime, I don't use it because I cannot stand the build, bundling step and the problematic debugging experience with source mapping (and difficulty to debug production errors where source maps are not available). If you write code correctly with loose coupling and good tests, static typing only provides marginal benefits.
Your last sentence is writing a very large check that I'm not confident at all you can cash.
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.
Thats weird, the best ppl in JS seem to be tearing TS out due to compile time/toolchain perf problems.
Do you have any large typescript projects?
I personally hate everything about the transpilation step; the time it takes (slows down dev-test iteration by a lot), the source mapping aspect, debugging in a live production environment (I hate having to debug transpiled/mangled JavaScript). I hate having to handle multiple permutations of engine versions (too many possible permutations of tsc and node.js version numbers which introduces configuration and setup difficulties; it rarely works out of the box; it's a nightmare for open source projects when you're potentially dealing with a broad range of different operating systems and environments which you have 0 control over; maybe the user needs tsc version x.x.x for some different reason and you cannot force version y.y.y onto them!!! So their tsc version will not work with your tsconfig)... It just adds a ton of bloat, dependencies (security/maintenance burden), setup/compatibility problems and the value it adds is marginal.
I think Typescript is here to stay, way more than Coffeescript was. On the other hand, I wonder if there's not a missed opportunity by compiling TS to JS. You lose all the type information that could be used to optimize the code.
How so? Coffeescript was mostly absorbed by JS, a true success story. 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. OP might be on to something, not wanting to waste time chasing trend n-1
Intertia. TS is way more popular than Coffeescript ever was, so there will be more code to maintain, and the network effect applies here.
Who are these people, why are they moving away from it?
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.
It seems to me that there is a divide of angular typescript apps that are about 3-5 years old and a new wave of react flow apps. Wonder what the stats are.
That might be just my bubble, but I've never heard of anyone using Flow, especially with React, whereas I often hear about React with TypeScript.
What do you see them moving to?
Linky: https://www.google.com/amp/s/startfunction.com/deno-will-sto...
This is just a Deno-specific internal thing due to tsc being too slow for their specific case. Deno itself can read and execute TS code and they aren't planning on dropping that.
Right, they just wouldn’t use it themselves.
In the original design doc: https://docs.google.com/document/d/1_WvwHl7BXUPmoiSeD8G83JmS...
TypeScript and JavaScript are the same language, and JS is definitely not going anywhere.