I know, but it just doesn't matter enough. Believe me, I'm signed up to the idea of theoretical rigour, the argument for soundness is part of what originally won me over (along with previous good experiences with Flow on a smaller project, and the support for gradual adoption). I will continue to be drawn to languages and tools that have a strong theoretical foundation. But in this particular case, today, when comparing these particular projects in the large JavaScript codebase I am talking about, TypeScript still wins by some distance. I promise that it has caught way more errors and been more generally helpful in its language server abilities than Flow ever was. Maybe Flow has caught up since then in its core functionality, I haven't been keeping track, but there would still be the wide disparity in community support which has serious implications for developer education, availability of library type definitions, etc.
I think the real answer is adding actually sound types to JS itself.
One of the biggest revolutions in JS JITS was the inline cache (IC). It allows fast lookup and specialized functions (which would be too expensive otherwise). These in turn allow all the optimizations of the higher-tier JITs.
The biggest problem of Flow and TS is encouraging you to make slow code. The second you add a generic to your function, you are undoubtedly agreeing that it is going to be accepting more than 4 types. This means your function is megamorphic. No more IC. No more optimization (even worse, if it takes some time to hit those 5+ types, you get the dreaded deoptimization). In theory, they could detect that your function has 80 possible variations and create specialized, monomorphic functions for each one, but that's way too much code to send over the wire. That kind of specialization MUST be done in the JIT.
If you bake the types into the language via a `"use type"` directive, this give a LOT of potential. First, you can add an actually sound type system. Second, like `"use strict"` eliminated a lot of the really bad parts of JS, you can eliminate unwanted type coercion and prevent the really dynamic things that prevent optimization. Because the JIT can use these types, it can eliminate the need for IC altogether in typed functions. It can still detect the most-used type variants of a function and make specialized versions then use the types to directly link those call sites to the fast version for even more optimization.
I use TS because of its ubiquity, but I think there's the possibility for a future where a system a little more like Flow gets baked into the language.
> I use TS because of its ubiquity, but I think there's the possibility for a future where a system a little more like Flow gets baked into the language.
Have you looked into ReScript? It is basically a sound type system + JavaScript-like syntax. It inherits the type system from OCaml. You might like it. They recently released version 11.
Maybe! I see where you're coming from. That sounds like a long and painful road, still, though, from what is still a very dynamic language. Do you have a rough idea of how much more time/space-efficient a typical JavaScript program could be through this?
JS uses a JIT while Ocaml is AOT which is generally an advantage for Ocaml.
Ocaml only compiles once while JS compiles every time it runs. This means that JS is a lot more selective about its compilation, but the hot code could be every bit as fast as Ocaml. On the flip side, Ocaml is fast because it compiles method-at-a-time and a SML compiler like MLton which does a slow whole-program pass can generate significantly faster code (despite being a part-time hobby project for a few academics).
The big difference is money. Ocaml has some funding, but nothing compared to JS. It's hard to believe, but handling strings in JS is probably faster than what most devs could do themselves in C/C++. It's not because JS is inherently faster. It's because those bits are native and have had countless man-years poured into making them fast. That said, even the JIT itself is top-tier and raw integer code is only 20-50% slower than C (excluding any SIMD optimizations).
I think the upper limit for a typed JS could be about as fast and maybe a little faster than Ocaml on the JIT and maybe even a little faster with a more restrictive subset compiling to WASM.