72 comments

[ 0.26 ms ] story [ 129 ms ] thread
Excited about “Higher order type inference from generic functions”. Great for libraries like RxJS, Ramda and axax.
The type inference looks good.

Pardon a question here: Will ES6 Code ‘just Run’ under TypeScript? I think the answer is yes for ES5, but I don’t know about ES6. Thanks.

Generally that depends on how many 'strict' compiler options you enable -- and whether you consider legitimate type errors a reasonable reason to not 'just run' your code :)

An example would be that classes that don't explicitly declare their fields will throw a type error when their fields are mutated (eg. `this.foo = 123`).

I believe Typescript is an extension of ES6.

TS is ES6 + types (and other things).

Not sure what you mean by running ES6 code under Typescript. It is my understanding that Typescript 'transpiles' to whatever flavor of Javascript you need, and then the code is executed as Javascript.

If your question is whether you can just change the file extension of a working ES6 file to .ts without Typescript complaining then answer is 'yes', you should be able to do that no problem.

Edit: of course there is little sense in doing nothing more than that, but it is a good starting point for decorating existing Javascript with TS features.

The biggest pain-point with renaming a ES6 file to *.TS is that TypeScript will flag every library or browser specific object you reference as missing.

That isn't wrong behavior on TS's part, just getting started with TypeScript is very configuration heavy, particularly for targeting browsers.

You can use the ‘allowJs’ flag to have the compiler accept unmodied JavaScript and for untyped modules you can use shorthand ambient module declarations so they use the ‘any’ type, with one line of code.
If your target is ES5 you will have to provide polyfills. Typescript will unfortunately typecheck even if you don't have polyfills and you'll get runtime errors with your ES5 target.

They specifically said they won't provide polyfills and they Will continue to typecheck even if your target does not support the standard function.

If you use classes, the compiler may complain because the class has no declared fields.

The compiler will emit JS anyway.

Class field declarations are a stage 3 proposal for EcmaScript, btw, and already supported in Chrome. So

  class Foo {
      foo;
      constructor() {
          this.foo = 42
      }
  }
Will be both valid ES2019 or ES2020 and TypeScript.
Wow. The const assertion is huge. My codebases are littered with things that I, the developer, know are constant but TypeScript does not and it often takes extra work to get type safety because of it. Can't wait to start using it.
Now following their examples clearly.

Why not just make that "let x" a "const x" which JS already allows?

"const a = {}" disallows reassignment to "a" but still allows you to mutate the object e.g. "a.b = 1". The const context does not allow you to mutate the object.
OK, the example with the "hello" literal string they have is quite bad then.
`as const` is useful there as well, as TypeScript’s type inference only narrows as far as the type and not the literal value. `let z = {text: "hello"}` has the shape `{text: string}`, with `as const` it has the shape `{text: "hello"}`.
Yeah, but shouldn't it use: const z = 'hello' and then get the shape {text: 'hello'} automatically?

Why use "let" along with "as const" instead of mere "const x = 'hello'" for that?

Because `const` is a js level keyword that has different semantics: it applies only to the reference binding being immutable, not the value as being so. `const a = "hello"` does have the shape `"hello"` as you’d expect, since strings are immutable in js and the `const` keyword makes the binding immutable as well. But objects are mutable, so TS can’t be a superset of javascript and change the semantics of that behavior. Hence `as const`.

This is different to the widening of value types within objects, which is a tradeoff made towards unsoundness with the belief that it would otherwise make interoperability with existing js too difficult, for which `as const` now serves as a way to explicitly opt into sounder behavior.

Frankly it's a bit of a nuanced improvement, but I've seen it come up enough times that it's nice to have a real solution. The big value in `as const` is that `'ON' as const` has type `'ON'`, while `'ON'` has type `string`. If you have a function with a parameter of type `'OFF' | 'ON'` (a union type of two literal types), then it won't accept `string`, so you can end up in situations where the string `'ON'` won't fit because it was inferred as `string` in an intermediate step.

Here's a concrete example. The `printSwitch` call fails because `state: 'OFF'` is inferred as having a `string` value. In TS 3.4, you could write `'OFF' as const` and it would work.

https://www.typescriptlang.org/play/index.html#src=interface...

TS is already pretty good about this, e.g. if you write `const s: Switch = {`, then it'll have enough context clues to know that `'OFF'` should have type `'OFF'`, but the new `as const` syntax is a way to explicitly say that the type shouldn't be expanded to `string`.

There has never been a worse time to be a software developer.

Practically all of the most popular tools encourage anti-patterns, add unnecessary complexity or solve superficial problems instead of focusing on critical problems that exist in today's software projects.

Some examples:

- TypeScript: Unfortunately, we cannot reduce a language's complexity by adding extra complexity on top. The complexity will keep rearing its ugly head no matter how much we try to hide it. The TypeScript project has had over 20K issues raised and 9K pull requests (that's not even mentioning the DefinitelyTyped repo)... To put it into perspective, the Linux project has only had about 380 PRs on GitHub. But how much value does TypeScript add? All evidence points to the fact that TypeScript does not have any positive effect on bug density. Its value is purely subjective and speculative. If humanity had invested a quarter of that time and energy towards coming up with and documenting proper JavaScript design patterns and architectures, TypeScript would have been completely redundant to begin with.

- NestJS: Makes heavy use of decorators; these aim to allow developers to handle cross-cutting concerns within their code. Unfortunately, cross-cutting concerns are an anti-pattern because they imply a violation of the principle of separation of concerns between components. It takes a bit of thinking and discipline to come up with components which have clear and distinct concerns/responsibilities, but this is not a problem that can simply be ignored by injecting decorators all over your code.

- InversifyJS: Dependency injection is a failed concept. It's been proven over and over. Angular 1 provided us with plenty of evidence for why we should avoid dependency injection (e.g. it's impossible to find stuff and you end up with a pseudo-global scope for everything which is as bad as simply using global variables). Again, dependency management is not a solution which can be automated away; it requires developers to make careful design decisions.

- Code coverage tools like Istanbul and others add very little value to projects. 100% coverage is not a useful goal to have, in fact it's counterproductive. When it comes to test coverage, quality of that coverage is WAY more important than quantity (this cannot be over-emphasized). Did you test all the right inputs? Do the tests focus on the most important code paths (and those which are more complex and therefore more likely to fail)? I'd rather have 10% quality coverage of the right parts of the code than 100% poor quality coverage. Also, you need to take into account that the more unit test coverage you have, the harder it is to make changes to your code.

- Linting tools such as ESLint/TSLint: These tools can be very nice if used correctly and not treated as a silver bullet for all programming problems. We should never forget that linters can only detect superficial problems. If your code passes all the most strict linting rules, it still says almost nothing about your project's code quality. I'd MUCH rather have code that fails ALL linting rules possible but has good architecture and good separation of concerns between components; at least the linting is easy to fix. Linting does not prevent architectural mistakes AT ALL; it only prevents superficial mistakes which are usually easy to identify anyway (if you have half-decent testing).

I hope that over the next decade, the masses of new developers will develop their critical thinking skills and that they will be able to see value beyond the hype which is always being shoved into their faces by various misguided organizations.

It's particularly difficult for me to see what has happened to software development because 10 years ago, I used to roll my eyes when I read comments like this from older and more experienced developers. New developers are often attracted to complexity like moths to a flame, but eventually we all learn that complexity is a silent killer - It's the ultimate...

> To put it into perspective, the Linux project has only had about 380 PRs on GitHub.

IIRC Linux does not use GitHub for project management or as a source of truth, only as a mirror.

This. Comparison with Linux is laughable, there have been orders of magnitude more patches to Linux than there are PRs on their GitHub.
Unfortunately, many popular projects get a lot more bug reports than the team can deal with. While this is annoying, it's mostly a measure of popularity, not quality. (Or at least, you need to adjust for popularity.)
You make some valid points on DI, linting, etc. but your first point on Typescript itself not providing value is pure FUD. Typescript catches a TON of bugs and the ones that are the most frequent https://rollbar.com/blog/top-10-javascript-errors/.

That we as an industry ship code (Javascript) to production that still has bugs that are so easy to catch at compile time does not reflect well on us, and your comment really does not help in this regard. What is your recommendation to ensure we catch more bugs at compile time rather than letting users find out that their application doesn't work?

Quality test coverage. I'm a big fan of having integration tests which cover all the main scenarios which are relevant to your users.

For example, one of my open source projects has about 120 integration test cases in total; these are enough to cover about 10K lines of code (not counting third-party dependencies); if I break any documented feature of the project, it's essentially guaranteed that many test cases will fail - They will catch the smallest issue or inconsistency; even things which are not being explicitly tested.

Integrations tests are great at detecting symptoms. They don't always point exactly at what the problem is, but they are great at letting your know that there is a problem and then you can debug it.

Integration tests are the best way to identify and fix issues in very complex systems. For example, when it comes to medicine and the human body; a thermometer reading is an example of a well-designed integration test case; if your temperature is high, then the doctor knows straight away that you have a problem which needs to be addressed. The doctor will probably not know exactly what the problem is immediately, but nonetheless, that simple thermometer reading (assertion) can allow them to detect the symptom of an essentially infinite range of possible underlying issues. One test case is not enough to cover all possible health problems, but the enormous amount of internal coverage that this single test case provides is unfathomable. We ought to try to come up with such test cases in our code.

If you have good integration tests, it doesn't really matter what language you use because (in terms of identifying issues) everything else pales in comparison.

Also it's important to note that integration testing doesn't necessarily mean end-to-end testing. You can still mock certain external components or engines in order to get more stability in your tests and you can still get that same kind of leverage.

How long does your integration test suite take to run? I have (many) typed interfaces and an editor running the language server. Typos, bad imports, etc are highlighted instantly and inline so they get fixed right away. Even better, autocomplete and refactoring tools know about these types, so typos and refactoring mistakes are vanishingly rare in the first place.

I agree that this does not replace integration tests or manual QA (dependencies can break and not every behavior can be checked). But as a lever for increasing productivity, a type system (even with the added complexity) is unbeatable.

Basically my point is that you aren’t actually catching errors at compile time, you’re catching them at build time. Your workflow might provide the same guarantees for the code that gets deployed to production, but writing that code is probably less enjoyable and you’re probably less productive than you could be.

I think the most effective way to find a bug in a program is to demo it in-front of a crowd. Or let grandpa use the program. Jokes aside, I think the most effective way to catch bugs is to have many people read (and understand) the code, and also have many users hit the code paths, most bugs will reveal themselves given enough time. Well used/tested code is often referred to as "hardened".

You wanted to find the bugs before shipping it to users, and that is also what I used to pursue, but when you let a ton of users hit your code, they will find the issues way faster then you could. It's however important to log, and debug all errors, and have a channel for users to submit issues. Sure it will be annoying for the user when he/she stumbles on a bug, but you will regain the goodwill when you fix his/her issue. In most software, even today, users are used to wait months, and even years, or infinitely, to have a bug/issue fixed. So it's a lot of "WOW! Thanks" And very little "I will sue your ass". Bugs, if you do actually fix them, will have a net positive effect.

Any thoughts on ReasonML, Scala.js, Purescript...

The functional attempts at Javascript

It only gets interesting to me when browsers (or for that matter node) get tail-call optimization.

Until then iteration makes way more sense than recursion in JS.

Type safety has been proven to increase programmer productivity long-term, allows code to be partially self documenting and prevents bugs. I don't think that we need that discussion again.

But in general I agree with you. If you adopt a tool, any tool, any framework you need also think about the learning curve and overhead you impose on the next developer and yourself. This is especially true if something goes wrong, you run into issues and you need to troubleshoot it.

> There has never been a worse time to be a software developer.

Quite the opposite! CPU and memory are cheap, FOSS is everywhere, and now more than ever its possible to create massive applications all on your own.

> Practically all of the most popular tools encourage anti-patterns, add unnecessary complexity or solve superficial problems instead of focusing on critical problems that exist in today's software projects.

> - TypeScript ...

TypeScript solves many problems with real world JavaScript applications at scale (code scale, not user scale!). Static type checks and interface validation are powerful tools. They lead to both more correct programs and faster development.

> - Code coverage tools like Istanbul and others add very little value to projects. 100% coverage is not a useful goal to have, in fact it's counterproductive. When it comes to test coverage, quality of that coverage is WAY more important than quantity (this cannot be over-emphasized). Did you test all the right inputs? Do the tests focus on the most important code paths (and those which are more complex and therefore more likely to fail)? I'd rather have 10% quality coverage of the right parts of the code than 100% poor quality coverage. Also, you need to take into account that the more unit test coverage you have, the harder it is to make changes to your code.

Depends on the type of code being checked. For a library meant to cover a huge number of permutations a coverage report can be useful. It's not a panacea for general application development. With static type checks a lot of the value of code coverage iseliminated as an entire class of errors is handled by the compiler (ex: "foobar" mispelled as "foobuz").

> - Linting tools such as ESLint/TSLint: These tools can be very nice if used correctly and not treated as a silver bullet for all programming problems. We should never forget that linters can only detect superficial problems.

That's literally the job of linting tools. To catch superficial problems as they're often a symptom of real problems. An unreferenced variable is either dead code (at best) or broken logic. Bad formatting and indentation could be purely cosmetic or a massive security issue (GOTO fail...). It's not going to tell you that your binary search is totally correct, but it will tell you if you forgot to reference the "high" variable entirely.

Tslint has in some cases evolved as a compiler extension. Things like "no-floating-promises" are huge and only really possible with sufficient type information.
Specifically addressing the “reducing complexity by adding complexity on top” point: the complexity is there whether you like it or not. The choice is whether it should be explicit and thus (to some degree) verifiable, or implicit and waiting to bite at runtime. TypeScript is a very solid improvement over JavaScript for this reason.
> But how much value does TypeScript add? All evidence points to the fact that TypeScript does not have any positive effect on bug density. Its value is purely subjective and speculative.

This is objectively false. There is plenty of evidence showing that modern type systems reduce bugs considerably.

In Airbnb, they found out that 38% (!) of bugs could have been prevented by using TypeScript[1].

Another scientific study discovered that TypeScript and Flow could prevent about 15% of bugs in committed code [2]. And these aren't even measuring reduction of bugs in non-committed code!

Stripe is also writing their own type checker for Ruby and engineers have reported an increase in productivity[3].

[1]: https://news.ycombinator.com/item?id=19131272

[2]: https://blog.acolyer.org/2017/09/19/to-type-or-not-to-type-q...

[3]: https://sorbet.run/talks/StrangeLoop2018/#/

Typescript also significantly reduces communication overhead and provides machine-verifiable documentation, making it way easier to figure out WTF is going on with unfamiliar or long-out-of-sight code. People who don't love TS compared with vanilla JS must work entirely differently from me—using it's the only time I've not hated writing JS. Tons of time-wasting poking about and background anxiety just gone. It's great, and costs almost nothing.
Typescript is a gamechanger with generated interfaces. We use it heavily with an RPC framework and pulling down the generated client and server packages have drastically minimized integration issues.

It just takes away the mental overhead of making something conform to a spec. It probably doesn't save us much on production bugs, but it makes development faster.

Generated interfaces are an anti-pattern. Types force tight coupling between clients and servers. What if a third-party project written in a different language wants to communicate with your server using their own client? Types will make it more difficult for them to integrate because:

1. If they're using a dynamically typed language, this gives them extra work to typecast everything back and forth whenever they need to communicate with your system.

2. Even if they use types, maybe their type system is not compatible with yours and they need to do a lot of tedious extra work to typecast everything.

what is the solution? runtime errors?
Huh? Everything always has a type anyway. It's sometimes just harder to know what it is. Specifying doesn't make the types appear out of nowhere, it just documents them.
I wouldn't call that an antipattern.

I treat other systems like I do the database and enforce consistency at the API level.

I wouldn't ask for a database to be totally untyped (and thus silently coerce things into its internal types in reality), so I don't ask for the same in an API.

Though, I can understand some people have differing preferences---MongoDB is popular for example---but I wouldn't call it an anti-pattern no matter which choice one makes.

No, it makes it easier, because they have a specification to work from, and they can probably just use that spec to generate their own glue code, assuming any is necessary.

I have never found option 2 to apply in any meaningful fashion, though I'm sure others have done much more of this type of work than I have.

I've found it to be annoying in the other direction. A type system like protobuf isn't rich enough for the problem domain. We end up building a lot of additional validation into the servers and clients that could have been enforced by the service/types spec.
Which is why our rpc services accept json in addition to protobuf. Yay, problem solved.
>> In Airbnb, they found out that 38% (!) of bugs could have been prevented by using TypeScript[1].

I don't buy these hypotheticals and also I don't believe in this kind of anecdotal evidence.

I think that the real root problem is that they didn't break down the code into logical components and didn't test them correctly - That was the real problem, not JavaScript.

When you look at reports of bug density across large samples of projects, it's clear that TypeScript does not solve any problems. See https://medium.com/javascript-scene/the-shocking-secret-abou...

> I don't buy these hypotheticals and also I don't believe in this kind of anecdotal evidence.

The only anecdotal evidence I've linked is Stripe's experience with Sorbet. The paper linked is an actual scientific analysis with great study design. I couldn't find the Airbnb slides or talk but an engineer involved claims the study was carefully designed[1].

> When you look at reports of bug density across large samples of projects, it's clear that TypeScript does not solve any problems. See https://medium.com/javascript-scene/the-shocking-secret-abou....

Go read the "study" referenced in that article. It's just blog post with a terrible methodology. It's basically

(number of issues with bug label) / (lines of code)

The author doesn't even normalize for LOC (larger codebases tend to have more bugs) or take into account project complexity.

[1]: https://twitter.com/swyx/status/1094857103863209985

EDIT: add disclaimer about airbnb talk

the problem with study like airbnb is that while tooling would have caught X% of bugs of type A, it in no way means those wouldn't just be replaced by bugs of type B.

bugs are (in part) function of code and tooling complexity, making some bugs harder to introduce doesn't reduce that complexity. risk compensation principle is another factor, and so on.

i haven't yet seen strong evidence that static typing really reduces bug density.

I would love to read the Airbnb study. Do you have a reference ?

The other study you referred to sponsored by Microsoft is very vague on the methods used to conduct the experiment. So its not repeatable. You can't say something is scientifically true unless the results are repeatable.

In your opinion, what are the critical problems that exist in today's software projects?
Unclear separation of concerns between components.

This is more of a problem for back end projects. Front end web development frameworks tend to enforce certain architectural constraints so there isn't much margin for error there but back ends and other complex projects are often terrible when it comes to assigning clear and distinct responsibilities across components.

> There has never been a worse time to be a software developer

> I used to roll my eyes when I read comments like this

Yeah, I rolled my eyes so hard at this comment, it hurt.

> All evidence points to the fact that TypeScript does not have any positive effect on bug density. Its value is purely subjective and speculative.

That is one of the weirder statements I've come across on this website.

First of all, there are tons of analyses publicly available — from well-known companies like Lyft, Airbnb, etc. — that document reduction in software defects solely from TypeScript's compile-time checks. (Source: uh, Google "TypeScript".)

Second, it is virtually impossible to code for a day in TypeScript without it catching bugs. Granted, many of them would be bugs that you would have caught as soon as you ran your program, but TypeScript catches them while you type them so you never do run the program with that bug.

(That's the secret actual reason it's named Type Script.)

You can not compare PR counts for Typescript to the Linux kernel.

The Linux kernel does not accept Github pull requests for development. If you try it, it will respond with this friendly message:

Linux kernel development happens on mailing lists, rather than on GitHub - this GitHub repository is a read-only mirror that isn't used for accepting contributions. So that your change can become part of Linux, please email it to us as a patch.

Yeah, do they really think that Linux has only ever had 300-something pull requests?
> starting a Typescript project is like accepting unnecessary complexity from the beginning

Dynamic typing is what really hides complexity. The higher order component pattern in React is a prime example. What seems like a simple idea is revealed to be extremely complex once you try to implement it using Typescript. Writing the types is a great way to get feedback on how complex your abstractions really are.

Deciding to use Typescript is about making a commitment to reveal and deal with unnecessary complexity from the beginning.

Especially true for generic types
100% agree. Simplicity. Big picture focus.

The buzzwords & flashy libraries add incremental value over ES6 with large organizational migration costs. For example 90% of Redux code is useless and a liability. But, devs think it’s cool and devs get what they want. Businesses will let devs tinker instead of loosing them. Hence complexity, inefficiencies and egos.

Build something useful in the simplest way possible.

P.S. When I write Typescript I NEVER get caught by the compiler because I KNOW what fucking type my variables are. There’s only a of handful natives becau se this aint C and my object instances are always well named.

I bet the majority of programmers don't write perfect code like you. But hey, no one is forcing you to use Typescript or any other library that requires you to stop using vanilla JavaScript or makes something so over complicated for you.

It is just like the CLI vs GUI thing, people want choices.

I haven't written anything in TypeScript, though I have some friends that love the language; I got annoyed at having to supply bindings for obscure languages.

If you can get past the initial hurdle, is TypeScript worth it for Node.JS stuff?

YES. I would never go back. Types, combined with a great IDE in VS Code, make for a so much less frustrating experience.
Typescript is a godsend. Once you get comfortable with TS, you just can't go back to normal JS.
what does bindings for obscure languages mean in this context? does TS count as obscure?
I'm guessing it's a typo for "libraries".
TypeScript doesn't require bindings to call JavaScript libraries. This includes writing code to run in the browser and writing Node.js code.

Instead, what you want are type definitions for the library you use. These are optional, but make using a library with TypeScript a much better experience. It is very common for these definitions be available already, whether the library is written in TypeScript or something else. Years ago I remember having to manage these type definitions, these days I don't really have to think about it much.

There's not much of an initial hurdle, to be honest. You're mostly adding annotations to your JavaScript code. It does influence the structure of your code but not as much as you might think, at least in my experience.

Just like @klodolph said, TypeScript to JavaScript is what C++ is to C, I.e it offers SUBSTANTIAL benefits while there are still some dark sides of the language to be discovered. (My personal view: TS metaprogramming is the hardest for me so far, enum mess, Babel TS preset lacking metadata support etc)
(comment deleted)
Oh dear, look at those features. Typescript is becoming the big valley of types and syntax overheads. In order to be productive, as a developer I should learn or know almost all the distinct syntax rules and tons of best practices.

An ideal (or close to it) typed language will have only few type rules and better way to compose them.

I prefer either ReasonML or PureScript

ReasonML is great if you are looking lightweight alternative for compatibility with existing JS libraries. It has relatively far less type syntax than TypeScript.

I find PureScript (which also compiles to JS) to be more succinct and solving the right problems for the developer. Although you need to spend some time writing monadic adapter layer over existing JS library API interface if you want to use them but given the confidence and safety provided by PS compiler, I think it's worth the time.

https://blog.functorial.com/posts/2017-08-09-Why-You-Should-...