Hacker News new | past | comments | ask | show | jobs | submit login
The TypeScript Tax (medium.com)
67 points by bnchdrff 8 months ago | hide | past | web | favorite | 115 comments

But if you’re in the position of deciding whether or not to use it, you should have a realistic understanding of both the benefits and the costs. Will it have a positive or negative impact?

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.

I don't know where this misconception started, but you can't just run javascript through a typescript compiler. There is a huge amount of valid javascript that is not valid typescript. Try something like `const testVar = {}; testVar.asdf = "asdf";`. Node web frameworks, for example, are based entirely off this ability to monkey-patch the request object.

I think grandparent was referring to the fact that you can tell the compiler to ignore type errors if you so choose. The TypeScript compiler is perfectly happy to compile the code in your example, if you disable strict type checking and treat type errors as warnings. On top of that, there are simple annotations you can add that let you silence warnings as they come up, e.g. `const testVar: any = {}; testVar.asdf = "asdf";`. This is not too far off from a linter with comments to disable linting when you don't want it. So yes, technically, you can just run JavaScript through a TypeScript compiler.

Sure... I guess you're saying that you can use the typescript compiler just fine as long as you turn off literally the only reason for it?

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"?

Yes. As a matter of fact, I'm currently working on a large JS codebase that is a decade old. We switched over all the code to TypeScript in one go, and we are gradually fixing the type errors over time. VSCode does an excellent job of showing you type annotations and type errors inline, so the typing is very useful even if you have thousands of errors elsewhere in the project and never even run the type checker globally.

In fact, out of the dozen or so TS codebases I've worked on, I've rarely seen one completely free of type errors. And yet no team has ever doubted the value of the type system. It's a very pragmatic approach which works very well for many teams in my experience.

I just finished something similar: http://caines.ca/blog/2018/12/11/a-javascript-to-typescript-...

We opted to keep it strict (no implicit `any`) through the entire transition but only apply it to ts files, so we are indeed completely free of type errors now. We only have 50 cases of (explicit) `any` in 85K+ LOC and they're in type def files.

Let me be the first person you've met to doubt the value of the type system. I do like the in-editor support, but you pay for it with about 25% more code.

I'm certainly not advocating undoing it, but I personally wouldn't do it again (though the team has mixed opinions).

Just curious: What's your test coverage like?

So how many errors were uncovered, and how serious could they have been?

It's in the blog post, but more were created by the transition than removed. There were less than 10 issues found and none were anything that users were concerned about.

The alternative is that the code exists but it has no warning to indicate the code smell. TS is clearly preferable to that. Further, you're wrong to suggest that blocking the code from running on type errors is "the only reason" for it. TS offers very nice autocomplete support that you can't get without it as well as jump to definition and yes, warnings.

Not advocating for this, but that's not too far off from how some C/C++ codebases work.

The compiler can most definitely type-check that code. It's up to you whether or not you want to ignore certain types errors. Want to ignore monkey-patching related errors? Filter out all lines from tsc that include TS2339.

I just wanted to say that I absolutely love the fact that tsc errors have codes, such as "TS2339".

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.

That's what the --allowJs flag is for.

Front page of the TypeScript website:

"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.

I'm not sure exactly what you mean by "not valid" but that example is absolutely valid typescript, and will compile perfectly fine.

By default, you'll get "error TS2339: Property 'asdf' does not exist on type '{}'.". Yes, the error can be disabled.

Yes, some code requires ratcheting down strictness even from the defaults.

`const testVar = {}` doesn't mean that the object is immutable, it means that testVar will never point to something else.

He's not saying that TypeScript complains because he thinks TypeScript considers testVar immutable here. TypeScript will complain because it will infer the type of testVar is an object with no properties, and `testVar.asdf = "asdf";` is an attempt to write to a nonexistent property.

Let me save a few minutes of your time. The author of the article believes that static typing is mostly a waste of time. Consequently, in his point-based model, he assigned that particular feature of the language +0.1 points. "Typing overhead", on the other hand, got -3 points. And then, after adding all the points, he unsurprisingly concluded that the overall score is negative.

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.

> Consequently, in his point-based model, he assigned that particular feature of the language +0.1 points.

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.

> In that case he's putting it up against TDD + code reviews

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.

The reasons you don't understand are clearly explained in the article (you can't skip them because 80% of bugs are not detectable by TypeScript), and if TypeScript actually could catch 100% of bugs, I'd rate it a perfect 10 on that point and the ROI would be game over. TypeScript would win because you could skip the other quality controls and save a ton of time.

I wish.

No, I read it. It's nonsense and your numbers are bad beyond any excuse of napkin-math. They're plain ol' down-home gibberish.

[edit] let me demonstrate: the most basic problem is that your numbers in various categories do not measure up to one another in any way that makes sense. -3 for writing typings, +0.1 for catching 10-20% of bugs that would reach production. Either you're having way more trouble writing types than you should or you have so few bugs that catching 10-20% of them isn't very valuable. Plus, read the thread. You just ignore all kinds of benefits of TypeScript (mostly benefits of having any, even half-assed, static type system on top of JS, period). If you like something else, propose it and compare TS to that. You're saying it's 1/10 better than vanilla JS with TDD + code review but 30x worse in terms of that benefit than JS when it comes to time spent adding types. 30. Times. That's just one example, the whole chart's a wreck in a similar fashion. Plus I bet if you ask on this thread folks will be happy to suggest + entries you simply omitted. See the ones suggesting (correctly) that static types make both TDD and code review, which you like, a hell of a lot faster.

In the worst case if some little thing you want to do won't work well in TS or is too expensive to type properly, write that piece in JS. Yes, that's terrible. [pause; significant look; raised eyebrows]. But it's not worse than JS. Obviously. And you can do that in TS. It's part of what makes it such an incredibly easy sell.

First of all, you're wildly over-stating the difference. The scale based on percent of time spent or saved. It's impossible on this scale to even say that TypeScript is three times worse than no types, let alone thirty times.

As for the bug reducing benefit, yes it's up to 20% if you do nothing but TypeScript. As explained in the article, 80% of bugs can't be addressed by static types at all, so you can't skip the other measures safely. The zero point includes the other measures, which easily cover 90%+ reductions, combined.

Since other measures catch type errors, too, we apply the TypeScript reduction after discounting the other errors caught. Even with the maximum benefit of the doubt, assuming TypeScript catches 20% of the remainder, it's still a small percent of a small percent. You get exponentially diminishing returns with each bug prevention measure you apply, and TypeScript can't catch the lion's share of bugs, so it's the only one that makes sense to leave out as a quality control measure.

Eric, my problem with this analysis is that 15% figure for bugs that would have been caught by TS only applies to the "public" bugs, bugs the programmer committed because apparently the code appeared to be working (to him).

But the majority of my bugs aren't "public", because I see that things aren't working when I run the code and don't commit it. With the combo of IDE just-in-time help/suggestions/reminders/enforcement, a lot of mistakes that I will catch at some point later by the "other means" you compare to, before I commit and push (which is the majority of my bugs) are prevented or immediately pointed out. Stopping them before they start instead of having them cause write-run-debug cycles, which will stop them before they are committed, is a huge advantage to me that won't show up at all in the "public" bug analysis.

"Immediately tells me things that I will eventually discover later by other means after wasting time" is a big, fuzzy category in which most of the value I get from several typed languages seems to hide from many analyses, even those that mention IDE features.

This is exactly my problem with the article. Public data is the worst data to rely your assumptions on in this subject. The whole point of the type-checker is to find problems and bugs before commiting the code and we will never have access to the real data because this happens all the time and people just fix the issues and move on with their lives

I don't think the author adequately addresses the positives of development velocity with Typescript. I find I'm able to read and write code much more quickly with Typescript than without, especially once I am beyond 50-100 loc. I doubt I _ship_ fewer bugs to production, but I certainly catch and fix my own mistakes much more quickly _as I go_, and am able to make more ambitious changes much faster when I have types on hand. Most importantly, I'm able to pick up and work effectively with other people's code without having to dip into their implementation or documentation as frequently. I honestly can't imagine doing javascript for a living any longer without access to it.

Yup. He didn't address the biggest winner for me -- the ease of refactoring code you wrote 6+ months ago without breaking everything.

I'm on a large codebase that transitioned from Javascript to Flow a few years ago (which is very similar to TypeScript, though nowadays I'd recommend TypeScript over it). Before we started using Flow, big refactors were extremely painful. It was practically guaranteed that we'd have to spend a week manually double-checking things, and then spend at least a few days finding and fixing bugs after deploying the refactor to users. Therefore we avoided refactoring at all costs. With Flow, we suddenly can refactor something, find the loose ends with Flow immediately, be sure about it, and be done with it. The difference between now and then is night and day. We can get things done so much faster now. The article author's experience is completely alien to me.

Agreed. My watershed moment was trying to refactor a custom charting library we had written in CoffeeScript. I was on the fence about TypeScript before then but that experience completely changed my view. All the nice little features of CoffeeScript paled in comparison to the utter misery of doing that refactoring.

I have all those benefits already. The zero point includes inference, lint, design review, spec review, code review, and TDD -- and you can't leave those out safely because 80% of bugs are not type errors.

With TypeScript I can make a change and immediately get a list of every single line I need to update. None of those replace that very key functionality.

> and you can't leave those out safely

Who's advocating for the replacement of code review, specs, and tests with TypeScript? TypeScript makes these things better, it doesn't replace them.

You can make the life of others more easy by always naming the same thing the same, eg always naming foo.bar foo.bar and you wouldn't need to annotate them, and everyone will know what it is. But if changing something means you also need to modify code at a lot of other places you have a architecture/pattern issue. Such a change should always be a semver major.

I get the same benefits from my other tooling. Lint and type inference provide real-time feedback similar to TypeScript, and TDD gives me continuous test feedback every time I hit save. That's the zero point on the ROI scale, and while I admit that well annotated TypeScript code does it a little better, it's not better enough to justify the cost.

If you haven't already written an article about your tooling, I think a practical guide would be well received. Not many users are aware of thees tools, which is why TypeScript is so amazing. I don't think most TS users use it because they like to annotate things, they use it because the autocomplete and editor integrations.

I generally wasn't impressed by his work, but learning that Eric Elliot changed his citations to suit his false claims for his article on TDD [1] has made me lose any form of respect for him

[1] https://twitter.com/Hillelogram/status/1084991487702691840

I cannot describe how infuriating it is to see hacks like this get publicity. Thank you for sharing that link.

I like this guy. It's like he's trying out for HBO's Silicon Valley.

I had not seen that before. I will fix the mistake.

I freaking LOVE Typescript.

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.

> Type safety doesn’t seem to make a big difference. TypeScript proponents frequently talk about the benefits of type safety, but there is little evidence that type safety makes a big difference in production bug density. This is important because code review and TDD make a very big difference (40% — 80% for TDD alone)...

> 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.

> I'm confused how people can advocate TDD and not like static types too seeing as static typing gives you robust automated tests for the minimal cost of adding type annotations every now and then.

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 trouble is most projects are NOT employing the other reviews properly. The study made no effort to determine the quality of the test and review process, and instead assumed that they had been done by virtue of the bugs being merged to the master branch.

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.

> The study made no effort to determine the quality of the test and review process

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 get the same real-time error detection and refactoring help from type inference, lint, and TDD. Lint and inference gives me real-time editor feedback, TDD runs automatically on file save.

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.

> because at least 80% of bugs are not detectable with TypeScript.

I give up. You're repeatedly using this figure in this thread in a misleading way to make it sound like what you're saying is more legitimate that just an opinion.

The abstract of the study you cite explicitly mentions this is a conservative estimate of effectiveness and ignores bugs detected in private:

> 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%!

The number they consider conservative is that TypeScript can address up to 15% of public bugs. That's a different number than the proportion of public bugs found ts-undetectable because they're not type errors at all.

There are so many important details about what this figure means and how accurate it is.

Would it make a difference if TypeScript was used before the code was committed? How does the subject domain of the project impact this figure? How do other testing and review approaches impact this number? Are public bugs of certain kinds more likely to be reported for certain projects?

It's highly misleading to quote this figure in such a simplistic manner without caveats.

> Type correctness does not guarantee program correctness.

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.

Actually, one of the benefits of strong typing (without side effects) is that the correct implementation is sometimes the only one that compiles.

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.

I've seen this happen for a handful of functions, but implementation correctness proofs for general applications are far beyond the expressive capabilities of TypeScript.

One thing I like about JS is that you dont have to think about types. It's an old convention in JS that you should be able to pass anything in and it will figure out what to do - instead of complain. JS has always had a test driven approach - test-code-test-code so you would detect if something is off. But the strictness do of course have trade-offs, for example being fast, easy and forgiving, vs forcing the developer to think hard and give errors if it's not exactly right. For example writing flight control software where an error can mean life or death. Or writing a web game that can be patched in less then five minutes. Maintainability and refactor-ability is all about developer process, it's possible to build a buggy unmanageable mess in a strong/ strictly statistically typed language, just like it's possible to write a fail proof distributed system in plain JavaScript (it's possible but hard in any language and JS might not be the best option).

> One thing I like about JS is that you dont have to think about types

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.

For both good and bad it doesn't matter if you give me an apple or orange, they are about the same size so, but you might have problems giving me an banana. Example:

const len = x => x.length;

Articles like this will certainly bring out the pro-Typescript people, so this got me thinking. I'd like to hear from people who tried Typescript and found they didn't like it for any number of reasons.

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.

The article is correct in that it's important to understand that typing your code has a cost - it's not just all magical benefits. Personally (personally - not for everybody) the cost is that it inhibits my initial experimentation. I don't KNOW what types things should be while I'm faffing around researching and experimenting in a new domain.

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 ;)

type IJustWantToExperiment = any

You could use the allowJs typescript flag and mostly use JS files at first; perhaps only typing a few models.

Typescript projects definitely give me the most pain. You regularly end up to the point you have to resort to 'any' after hours of looking for a stupid type definition. IMAO it's just one big waste of time, just landed a job with a good old JS codebase, what a relief. TS might help for junior and medior developers so they make less mistakes. But I'm pretty sure if you can code Javascript well Typescript only stands in your way when you want to create something. Imagine you give a painter a brush that doesn't allow to be used freely, that's what TS does to a good JS developer.

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",

> But I'm pretty sure if you can code Javascript well Typescript only stands in your way when you want to create something.

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.

you mean Python and Ruby like languages are unmaintainable and therefore deprecated? I rarely have a problem with maintainability in JS because of types, but I do have problems with poor constructs, poor readability, dependency issues and so on. It's a typical illusion of TS proponents that code becomes magically maintainable.

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.

There's more to maintainability then just adding types. Maintainability is a process not a language.

Yes, and TypeScript is an incredibly powerful tool to make that process easier.

It's like using a bandage to prevent an injury. Yes it's good to have, but it doesn't prevent anyone from writing unmanageable code. Contrary it can make it even easier to write unmaintainable code.

You can say that about literally any technology. Nobody's claiming TypeScript will fix all your problems and discover all the secrets of the universe: it's just a useful tool that well outweighs the overhead it adds.

I just don't like having to look things up, or remember them, or tell someone else about them, or make sure the things I told them or that they told me are still true six months later, or check manually that I haven't typo'd a variable name, and so on and so on, when a machine can do those things for me.

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.

When dealing with binary packages I have to do stuff like iterating over an object to see what it exposes. I guess typings (if one exist) help a lot there. But for open source code you can just look in the source. Looking at other peoples source code is the best way to learn, so don't let TypeScript take that away for you. The projects with non-existing documentation is often the ones most easy to use. Maybe because the source code is so easy to understand that no documentation is needed :P

Most developers coming new to JS are Java and C# developers. They want to keep their old tools, and methods. And Microsoft want to keep selling it to them. Which is my main concern, once you're in you are locked in.

One problem with the math for the ROI calculation is that catching a bug with a test is counted the same as catching a bug while you're typing the buggy code. Type checking lets you catch bugs sooner, thus more cheaply.

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.

Some good reasons for that:

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.

> TypeScript alone can provide at about the same speed

If writing your unit tests contributes less overhead than writing TypeScript types you're doing something horribly wrong.

It's not less overhead, but you can't skip TDD with TypeScript because at least 80% of bugs are not detectable by TypeScript.

Before I tried Typescript I thought it was just another JS-precompiler... been there done that. I tried Coffeescript, the Closure Compiler, even LispyScript. In the end it wasn't really that much different to plain old JS, just with some syntactic sugar.

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.

I would say that there's no Typescript tax. Rather, there's a Javascript tax for Typescript. As in, the shortcomings of Typescript only come from Javascript. Typescript is transpiled to Javascript, so types are not enforced on execution, and that's the only real limitation of Typescript.

Usage of the word "tax" is interesting, too. I'm happy to pay tax if I reap tangible benefits from it / if the "money" is put to good use. I'd say that's the case with typescript.

What about Typescript clicked for you that didn't click with the Closure Compiler?

Hmm, its been a while since I last used it...

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.

He asks the question "But should you use it for your large scale app development project?"

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.

It pays dividends long before the end.

My usual "time to 'oh thank you typescript'" is roughly 2 days from the beginning of the project.

Typescript is the best thing happened in my developer life. I can clearly say that Ive observed 99% undefined type errors reduction in js runtime comparing to vanilla js.

For any JS that is over 100 lines, I will use Typescript without thinking.

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.

If you write 20% more bugs in pure JS you definitely should re-evaluate your skill. I'd never hire someone saying that to me.

You should probably re-read the comment, because that is not what he's saying ;)

If you write 6 bugs on 1 million locs of vanilla JS and 5 bugs with TS enabled, he can work for me in vanilla JS.

> Missing Features — HOFs, Composition

Uh... I'm pretty sure I've used both in TypeScript projects.

This was the most infuriating part. He either doesn't understand what a hof is, is actively lying, or just hasn't even used typescript long enough to understand this is incorrect.

Please show me the proper typing of the map transducer in TypeScript. I'm willing to learn.

It would seem that someone's done it already: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/mast...

Yeah, I use both all the time.

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.

One thing I really like about Typescript in strict mode is enforcement of handling null and undefined properly. Handling the stuff that usually isn't null is quite error prone as it typically works fine with well-formed data and only breaks once it encounters the real world with unexpected data.

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.

> "But should you use it for your large scale app development project?"

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.

I hope I’ve got this right, but if the author is comparing typescript to a modern tooling environment, while there are technical differences, I may not trust those maintainers more than Microsoft at language design and support.

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.

Those tools have a negligable learning curve because once you set them up, you can simply forget about them and write JavaScript code.

A thoughtful article this is. Heck, I like Typescript. I've used it in extensive experimentation and would gladly use it in production if a client or employer insisted on it.

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.

Put aside the scoring and conclusion parts, the author has a couple interesting observations that resonate with me:

> ... 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.

I think the author gets the detectable 15% wrong way around. TS detecting 15% on average due to annotations means we're finding at least those. Then we have the possibility of detecting all the bugs caught by potential better design. With the example of stringerror for an invalid url, you have two options: it was an accident (broke a url while processing) or misunderstanding (put a non-url text in the string). The second case may be still caught at a higher level by having better containers, better enum, lower chance of using ad-hoc bare object, interfaces which prevent you confusing types of string you're operating on, etc.

Going beyond just adding annotations is not what the references study attempted to do.

When WebAssembly will be feature-complete and without the need to call JS for every DOM or API access - developers would be able to just use the proper programming languages, like Rust, OCaml, Haskell, etc, instead of relying on buggy JS universe.

For those worried about compile time for large projects, tools like https://github.com/alangpierce/sucrase can go a long way for the transpilation (remove types), while you can use the TypeScript compiler in parallel only for the type analysis.

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.

Could have been titled "static typing vs. dynamic typing" but I guess TypeScript is more clickbaity.

My experience with TS is totally on the backend.

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.

> 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).

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.

> 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.

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.

Defensive programming is very effective in JavaScript. If the state is wrong, log, (core-dump) and restart. Trying to prove correctness statically is not a battle you can win in JavaScript. Instead enjoy getting things done. And let the bugs find themselves, using Murphy's law. For example:

    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.

This is a good analysis in the "JS or TS" domain, but it's of course seldom the only option to consider. TS competes with languages that compile to JS, so Elm, ClojureScript, Scala.js, Kotlin, etc.

All bugs are type errors they say, but how did they pass the type checker ? ;)

Type system is like a seat beat, its not going to save your from a head on collision with 18 wheeler. But it will mitigate you pain and suffering in small to medium accidents.

Yesterday, there was news that Facebook was porting Yarn from Flow to TypeScript for ease of new contributors. That ease is a shared goal of one of my projects, and yesterday I tried porting it as well.

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.

Huh? It sounds like a problem with your toolchain, not TypeScript. You should get all of that whenever there's a type error.

I don't think it was a toolchain issue, because I did receive line and file information for certain classes of errors. Presentation of that information doesn't appear to be pervasive.

Here's Eric Elliot, doing his Eric Elliot thing. Pages and pages of beautifully worded, perfectly structured arguments about absolutely nothing. And this month he's a Distributed Systems Expert. More power to this guy for building a brand for himself, but what a load of nonsense.

> Pages and pages of beautifully worded, perfectly structured arguments about absolutely nothing.

I don't know Eric Elliot, but this sentence captures my perception of most "influencers" perfectly.


Hello. Eric Elliott here. Which codebases were those, exactly?

Hi Dilvie, it's been a while. Mechanized was the first. The second was a job board type application I'm still under NDA for.

Not AP,

But I'm curious, can you Tldr the tax for typescript?

I skimmed half the article but I couldnt actually find what the tax was?

In similar vein to the above above poster, you might find this lecture useful: https://youtube.com/watch?v=vtIzMaLkCaM

Your writing has a very nice cadence to it I'm just not sure you grasp the reason I might want to read it!

I didn't notice the name, but came to say the same thing.

After skimming through, It's obvious that reading this article would be counterproductive for anyone with any sort of interest in this topic.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact