I strongly disagree. You can start using typescript without thinking for a second about what parts of it will be beneficial.
Initially you can just run javascript through the typescript compiler and let type inference find some bugs. You can start adding types in places where you want autocomplete to work better. You can ratchet up the strictness if you start to find bugs that stricter type checking would have caught. If you've read any typescript discussions on HN you already know this.
On the flip side, obvious once you think about it, the option is always there to ratchet down strictness if for your codebase the requirements turn out to be too heavy, i.e. slowing feature development down more than the bug reduction warrants. But you don't have to think deeply about it in advance. Just write your code, and every so often take a step back and look at how well things are working. Then adjust based on actual benefits and costs, not some premature estimate of them.
Have you been on a team that adequately managed a list of thousands of warnings, always finding and fixing just the ones that are "important"?
This is a fundamental part of error handling and DX that, unfortunately, is left out 10 out of 10 in tooling, applications and libraries alike, in special opensource projects.
"TypeScript is a typed superset of JavaScript..."
"Use existing JavaScript code, incorporate popular JavaScript libraries..."
You should be able to use --allowJs and have everything compile just fine, otherwise log a bug.
Note I'm not pro or anti myself, I've only just begun playing with it, but would like to hear from all kinds of people.
I'm a huge fan of strongly-typed code, but I like to add the types much later, once all of the pieces are in place and are not in constant change, and mostly as a way to not have to write unit tests. If I type from the start I find I lock in to sub-optimal data structures and get "attached" to them. I already typed them, I don't want to break things!
Also, I live by the "What Would Rich Hickey Do?" school of thought... so when he mandates types in Clojure, I'll switch to TypeScript by default ;)
You could use the allowJs typescript flag and mostly use JS files at first; perhaps only typing a few models.
But TS is at this moment really eating JS jobs, and that kinda hurts. I just don't understand the proponents, besides the job opportunity, give me one single reason to write in TS? If you want to go for a strictly typed language TS is definitely the worse choice. TS simply doesn't fit in the JS ecosystem. Look at (a part of) the dependency part of this package.json, from the beginning of a large project. Don't you agree something is going very wrong in the JS world?
"ts-jest": "^23.1.3",
"ts-loader": "^4.5.0",
"ts-node": "^7.0.1",
"tsconfig-paths-webpack-plugin": "^3.2.0",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.14.0",
"tslint-react": "^3.6.0",
"typescript": "^3.0.1",
"typings-for-css-modules-loader": "^1.7.0",
"@sentry/browser": "^4.0.0-beta.12",
"@sentry/node": "4.0.0-beta.12",
"@sentry/types": "^4.0.0-beta.12",
"@types/autoprefixer": "^6.7.3",
"@types/classnames": "^2.2.6",
"@types/clean-webpack-plugin": "^0.1.2",
"@types/compression": "0.0.36",
"@types/cookie-parser": "^1.4.1",
"@types/cors": "^2.8.4",
"@types/cucumber": "^4.0.4",
"@types/enzyme": "^3.1.13",
"@types/enzyme-adapter-react-16": "^1.0.3",
"@types/enzyme-to-json": "^1.5.2",
"@types/express": "^4.16.0",
"@types/helmet": "0.0.38",
"@types/html-webpack-plugin": "^3.2.0",
"@types/jest": "^23.3.1",
"@types/js-cookie": "^2.1.0",
"@types/memwatch-next": "^0.3.1",
"@types/node": "^10.5.7",
"@types/node-sass": "^3.10.32",
"@types/optimize-css-assets-webpack-plugin": "^1.3.3",
"@types/react": "^16.4.11",
"@types/react-dom": "^16.0.7",
"@types/react-helmet": "^5.0.7",
"@types/react-intl": "^2.3.10",
"@types/react-loadable": "^5.4.1",
"@types/react-redux": "^6.0.6",
"@types/react-router-dom": "^4.3.0",
"@types/redux-mock-store": "^1.0.0",
"@types/serve-favicon": "^2.2.30",
"@types/webdriverio": "^4.10.3",
"@types/webpack-merge": "^4.1.3",
"@types/webpack-node-externals": "^1.6.3",
"webpack": "4.19.0",
"webpack-assets-manifest": "^3.0.2",
"webpack-cli": "3.1.0",
"webpack-dev-middleware": "^3.1.3",
"webpack-dev-server": "^3.1.5",
"webpack-hot-middleware": "^2.22.3",
"webpack-merge": "^4.1.4",
"webpack-node-externals": "^1.7.2",
"stylelint": "^9.5.0",
"stylelint-config-prettier": "^4.0.0",
"stylelint-config-recess-order": "^2.0.0",
"stylelint-config-recommended-scss": "^3.2.0",
"stylelint-scss": "^3.3.0",You and the author are both overly concerned about writing code and completely ignoring maintainability. If you write your code once and never touch it again, sure, use plain JS. If you're going to come back in six months month and refactor it or hand it off to a co-worker and expect him to write some code TypeScript is a godsend.
JS developers moving to TS should at least do a few weeks of Assembly and C programming to first understand the origin of types. I've spoken too many front-end devs who don't have a clue what a type actually is and at the same time promote TS. It's a godsend we don't need them in scripting languages. Use tooling to catch issues, that's the future, TS is just a whim.
The absolute worst case with TS is that I'm as bad off as I would be in JS (use "any", or "as", or provide a dummy anything-goes d.ts for a lib, or whatever). I haven't found that I actually need to do those things very often, even being fairly lazy and having a very low tolerance for time lost to managing my tools.
Yeah, obviously. Think about it -- when you write the code you still think about the "types", you're just not writing them down.
Typescript's virtues are completely related to developer productivity. Documenting your code with types, better autocompletion, catching silly mistakes before needing to run it in a browser, getting new people up to speed, etc.
For example, if you know that a function takes a generic list and returns an integer, then the list’s length is pretty much the only non-trivial computation it can perform.
This is patently wrong. You _are_ thinking about types. Every object, function, variable you write has a type you store in your head. The question is about how easy it is to remember those types in 6 months, or how hard it would be for a new developer to figure them out.
> JS has always had a test driven approach
Yes, and you should keep that test-driven approach with TypeScript. I'm not sure why anyone would assert otherwise.
const len = x => x.length;
> TypeScript is only capable of addressing a theoretical maximum of 15% of “public bugs”, where public means that the bugs survived past the implementation phase and got committed to the public repository, according to Zheng Gao and Earl T. Barr from University College London, and Christian Bird from Microsoft Research.
The devil's in the details for studies like this and people ignore this to make it look like their opinion is backed up by science when it isn't. Measuring what percent help type safety gives in general is an impossibly vague concept while also very difficult to test, especially when making comparisons between numbers.
From the second study for example right in the abstract:
> Evaluating static type systems against public bugs, which have survived testing and review, is conservative: it understates their effectiveness at detecting bugs during private development, not to mention their other benefits such as facilitating code search/completion and serving as documentation. Despite this uneven playing field, our central finding is that both static type systems find an important percentage of public bugs: both Flow 0.30 and TypeScript 2.0 successfully detect 15%!
15% is a minimum from that study then and it isn't counting bugs that were caught from manual testing or otherwise before making a commit, or how much time was saved.
Quoting the study in this way is incredibly misleading in my opinion.
For me personally as a TDD person, I just don't care about testing types. I test values. The type-checker just doesn't do much that I actually care about (better in-editor support is nice though). I know it's not a fashionable answer these days, but for me it's true. I don't see the pay-off in doing both, and types alone are not enough.
The study then finds that about 80% of the bugs they found were not simply ts-undetectable, but not type errors at all. Instead, they're things like the wrong URLs being used (sting errors), wrong branching logic, wrong predicate logic, etc.
That means the maximum effect must be less than 20%, but the authors couldn't detect 20% even knowing exactly what the bug and fix was, down to the line numbers and exact code used to fix the bug.
Even being extremely generous and assuming they could fix 20% of remaining bugs, it's too far down the ladder of exponentially diminishing returns to make much difference at that stage.
Assuming you wrote the article, why did you cite that study then?
> That means the maximum effect must be less than 20%
But what effect are you trying to argue? Maximum of what? I feel this is so vague it's not useful.
In my opinion (I'm not going to try to back this up with a study that doesn't measure exactly this), types make an enormous difference while you're in the middle of development before you commit anything: they're capturing cases where you forget a variable could be undefined, when you mix up items and lists, when you want to aggressively refactor, when you forget to pass required parameters etc. Type annotations are rarely required and for the few minutes I take to write them I easily make that time back even in the short term. Only looking at the bugs that get committed (which is super hard to measure) is missing out on a big aspect of the benefits.
You also need to consider that code reviews and writing TDD tests are time consuming to do as well.
I do consider TDD and code reviews are costly but you can't skip them with TypeScript because at least 80% of bugs are not detectable with TypeScript.
But when I actually had to use it in a project, I instantly fell in love with it. Not only does it force me to think about the proper scope and type of a function or variable, it also helps refactoring and reading undocumented code.
Yes, sometimes it can be frustrating (meh: no typings for a legacy project, build-toolchains have to handle another layer of abstraction, etc.). But this really is peanuts compared to the hoops we had go through before.
TS has been the best thing that has happened to JS-development in the last decade.
But I'd say it simply has a different scope: The Closure Compiler takes a subset of Javascript and creates highly optimized code. It optimizes the execution, not the development workflow.
Typescript forces you to think differently about the implementation itself. While the CC also imposes constraints on types and checks them during compilation, in the end I really just wrote Javascript (and sometimes pretty messy one).
In the end, I don't think either technology can be a substitute for code quality. But for me, with Typescript its certainly easier to produce a better coding style.
Uh... I'm pretty sure I've used both in TypeScript projects.
I will admit I have to pass type hints via generics to my compose / pipe calls more often than I would like, but it definitely still works.
If you agree with the premise that static typing is a waste of time, you'll probably agree with the rest, but then you're likely not using TS in the first place. If you don't agree, the article is just wrong.
That's because his stupid chart is comparing a bunch of different things to TS instead of just comparing it to JS. In that case he's putting it up against TDD + code reviews, for reasons that I entirely do not understand. His numbers are so wildly incommensurate that they don't even make sense for any sort of informal water-cooler analysis.
[EDIT] if... if I'm reading his reasoning for that 0.1 score correctly, he'd still give it a -3.9 ROI if it caught 100-friggin-percent of bugs that would otherwise reach production, unaided by any other tools or practices. WTF.
[EDIT EDIT] for reference, that means he rates the overhead of noting one's types at 3x as bad as the benefit of magically catching 100% of bugs would be good. This is what I mean by these individual values being ZOMGWTF incommensurate.
Not to mention that TypeScript makes it easier to do both. Code reviews are easier when you can read the types instead of trying to infer them by reading the code, writing tests is easier when you have type-safe test data.
I wish.
[1] https://twitter.com/Hillelogram/status/1084991487702691840
Another problem is that it focuses on bugs that make it out to production. Maybe for some projects production bugs are so costly that pre-production bugs are relatively negligible, but for most projects you can't treat pre-production bugs as 0 cost.
1. I get type feedback in my browser with inference. 2. I get near real-time feedback from TDD on file save. 3. I get real-time lint feedback, too.
The net result is I get several multiples better bug coverage than TypeScript alone can provide at about the same speed -- while writing idiomatic JS.
If writing your unit tests contributes less overhead than writing TypeScript types you're doing something horribly wrong.
This is 20% for bugs, and 80% for sanity in long term maintenance. Refactoring is so much better / safer when you have a compilation process and at a minimum, types.
I just wish I could use Typescript without npm.
The biggest issue with typescript, and the reason I'll probably never reach for it for another large project despite having used it for a 50k line+ project, is that it's still, at its core, javascript. We've experienced a tremendous amount of pain because of this.
- We've needed libraries which don't provide typescript typings. Like a good little typescript user, we have strict mode enabled, which means we have to build our own typings when we encounter this. We've had library maintainers reject our typings we provide back to the community. We've had library maintainers say they have no desire to provide any support to typescript users because "its a fad" and "ts is just js, you don't need types, live with it" (not joking, not exaggerating).
- All of the good high-level JS frameworks and architectural libraries are built for, well, JS. So, you want to adapt them for TS, but the JS idioms are so core to their design that you throw away any benefit TS gives you. Express is a good example; you might have middleware which parses a bearer token and attaches it to the request. When the request hits the next middleware or request handler, its just a normal request. There's no way to assert at compile time that "this middleware came before, the request is now a new type with this extra field". Express, Apollo, the list goes on.
- Further, the community around creating Typescript-native libraries is exceedingly small and, as far as I can tell, dying. I'm talking libraries that are made for typescript and make use of the true end-to-end compile-time verification typescript gives you. TypeStack is probably the leading organization (on GitHub) which builds (amazing!) projects like this, and their velocity is slowing down. TypeDI hasn't seen an update in nine months. Vesper was an incredible web framework that hasn't been touched in a while. There's nothing available for MongoDB if you use that. Basically, you're stuck with JS native projects 90% of the time, and about 10% of those don't have typings available.
- We've had NPM libraries redefine the Error global. This isn't caught at compile-time, obviously, and totally borked the error responses our API sends.
- It's a constant uphill battle with the `as` keyword. I wish there was a way to easily ban it globally. You can essentially assert Anything As Anything, and if its not caught in review you'll end up with incredibly hard to trace behavior because "the compiler says this field should be there, why am I getting undefined"... well, its because sixteen layers down someone asserted a type without verifying its accuracy at runtime, and in 5% of situations its incorrect, and it missed review.
- It's a constant uphill battle with lodash. We have developers on some teams that swear by it, and will scatter `_.get`s all over the codebase, then be startled when things break in unexpected ways. Typescript added the `!` operator, which is basically just an escape hatch, and it took us a long time to get everyone educated that this is, without a doubt, the dumbest thing Microsoft has added to the language because it doesn't actually do anything at runtime, it just suppresses a potentially useful compiler error.
In summary, don't pick Typescript for the backend. It's an obvious improvement over JS, but you'll still be left wishing you hadn't.
But I also don't know what the better option is for a high-velocity organization. Go and Rust are too unproductive. Ruby and Python aren't performant and aren't strongly typed. JVM languages are a pain. Elixir shows a lot of promise but the lack of typing concerns me.
Why did you submit the types directly to them rather than to DefinitelyTyped? It's great when libraries maintain their own typings, but TypeScript handles the case where they don't really well.
>Express is a good example; you might have middleware which parses a bearer token and attaches it to the request. When the request hits the next middleware or request handler, its just a normal request. There's no way to assert at compile time that "this middleware came before, the request is now a new type with this extra field". Express, Apollo, the list goes on.
Yeah, this can be a pain. In situations like this, I've defined types like `type RequestWithAuthField = Request & {auth: AuthField};` and then in handlers that I knew came after the auth middleware, I'd immediately cast the request parameter to that type. It is an escape hatch and I'd prefer to not have to do that though.
>Further, the community around creating Typescript-native libraries is exceedingly small and, as far as I can tell, dying.
Besides that they're sure to avoid TypeScript-unfriendly APIs (unlike Express), I don't think there's much difference between a library with good type definitions and a TypeScript-native library. (Maybe the library could have bugs that it being authored in TypeScript would have avoided.)
I don't fully disagree with your points. There's a lot awkward about TS on the backend, but at the same time there's not much quite like it.
I find this less than ideal, of course, but still not worse than writing the same in plain JS, since at least this way the next person to come along (or you, a few months later) has clear guidance re: wtf is going on with those weird extra fields on the Request object. It's less effort—for reader and writer—and is more maintainable than expressing the same information as effectively in docs and comments.
if(x<1) throw new Error("This should never happen: x=" + x);
If it can happen it will happen. So instead of support getting a call that some customers balance is negative, with defensive programming you not only prevented the bad state from spreading, you can also see why it happened. And fix it asap. Meanwhile if you trusted the static analysis good luck and have fun debugging something after-the-fact that "couldn't" happen.I discovered that in contrast to Flow, TypeScript has horrible errors. Often I ran into errors that would not give much more information than "error" -- no line information, no file information, nothing. One of the causes of such opaque errors was empty Flow-style typecasts, so they were pervasive throughout a large project.
In contrast, Flow has beautiful error messages.
I don't know Eric Elliot, but this sentence captures my perception of most "influencers" perfectly.
After skimming through, It's obvious that reading this article would be counterproductive for anyone with any sort of interest in this topic.
I thought that was literally the reason TypeScript came to be. Microsoft were having lots trouble wrangling Bing web app and internal MS devs wanted a tool to help catch the bugs!
I would say, if you are embarking on a large scale app, you most definitely want to include TypeScript from the start. It will pay dividends in the end.
My usual "time to 'oh thank you typescript'" is roughly 2 days from the beginning of the project.
I don’t think you can write off the cost of learning all of those different tools in the non-Typescript environment. Typescript at least centralizes everything and I trust Microsoft to do good language development because of C#’s legacy alone.
I shipped an app about 90 days ago based on Typescript.
It's basically a document manager which supports annotations, comments and keeping your documents in the cloud.
Typescript was a MASSIVE win. If you're on a simple code base doing a refactor is easy. Anything significant and it's a nightmare.
If you change an object method JS won't complain.
With Typescript and IntelliJ or VS Code it's just a simple refactoring and your code just works.
I would have probably given up on the project had it not been for TS.
Would I use Typescript for my own production use? Likely not. My perception is that it is yet another layer of complexity added to front-end development that, ultimately, does not need to be there.
Another very useful part is that refactoring becomes much easier, as you can simply follow the errors when you break an interface other parts of your code are relying on.
Typescript forces me to be more disciplined when coding, and that is clearly a good thing in my opinion. There are probably cases where you don't want that, e.g. rapid prototyping, but otherwise it's very useful.
This seems to imply that for whatever reason, TS may not be suitable in larger projects, but both Vue.js and Visual Studio Code are full TypeScript projects.
> ... but conscientious developers will be interested in doing things right. They’ll spend hours Googling for examples, trying to learn how to type things that TypeScript simply can’t type properly.
> ... if you only need to hire one or two developers, using TypeScript may make your opening more attractive to almost half the candidate pool.
On the other hand, it seems that the author worked on a few medium-size projects and then moved on:
> All projects for which impact was judged were >50k LOC with several collaborators working over several months.
So I wonder if he was able to evaluate the impacts from a longer term perspective, which shall include refactoring experience, iteration speed, developer morale, etc.
Going beyond just adding annotations is not what the references study attempted to do.
That said, Sucrase has a number of issues still. Nothing that can't be resolved, but enough to prevent me from using it in a few projects.