Hacker News new | ask | show | jobs
by egeozcan 2884 days ago
Seems to use Flow instead of Typescript. I wish MS and FB just merged their projects already. Really unnecessary friction when their syntax is 90% the same AFAICT.
3 comments

Yes. I wonder what's the future of Flow (even if it's still used and maintained). As I posted in another topic about TS:

> It's kind of crazy that Facebook has let TypeScript takes so much market share. I've been using Flow for so long now. The techno is good, the integration with the code editors is good too, but Flow has a lot of small-but-really-annoying bugs (2235 issues on GitHub right now), the type definitions for third-party libs are meh (you often have to update/fix the definitions by yourself), the team seems extraordinarily unstaffed for such an important project, they don't share the roadmap at all, the priorities are clearly internal first (like improving the performances instead of fixing the bugs) and they don't seem to do much marketing or communication about it.

> I'd love to still recommend Flow, and as I said the techno is good and does the job, and they continue to release new versions, but I just don't see what benefits you would get by choosing Flow over TS at this point. Flow and TS do exactly the same job, with almost the same syntax (with different ways to transform it in JS tho), but TS has a bigger community and MS seems to put more efforts/resources into it. This has been true for 1 or 2 years now, so…

As I replied in that same thread:

> I tried Flow and TypeScript for the first time a few months ago. Flow is absolutely abandoned and dying. TypeScript is taking over where Flow left off, and is far ahead of the game by now. I use TypeScript with create-react-app in my client work and it is invaluable and a wonderful experience, with no downsides as far as I can see.

To add to that, the only reason I can see to use Flow in 2018 instead of TypeScript is if you already have a large project that uses Flow and migrating to TypeScript might take a few days. But even then it's probably worth making the switch. I have noticed a much smoother experience and much better integration with TypeScript than with Flow. And there are many type errors that Flow never caught no matter how much I tried to configure it right. Existing code bases may have these too. Even more reason to switch sooner than later!

We are in the process of doing this on a moderately large product. We've found TypeScript itself has much less friction to write (quicker development), and has a lot less gotchas (probably because it restricts the language itself, unlike Flow), so porting the code has been a big task but a very positive one. We went with Flow originally because it would work with our untyped JS better, but in hindsight we should have bitten the bullet earlier and gone straight to TS.

We're still exporting Flow types generated from TS modules to be imported by older projects (which is... _okay_). I would recommend just choosing the better option from the outset. You'll save hours researching why Flow has a problem (and eventually just writing `// $FlowFixMe <https://github.com/some-flow-issue/666` and moving on). I don't see any compelling reason to start a Flow project these days.

We chose Flow for a number of reasons. One of the main ones is type inference. For example:

https://www.typescriptlang.org/play/#src=function%20a(x)%20%...

https://flow.org/try/#0GYVwdgxgLglg9mABAQwBQA8CUiDeAoRRAJwFM...

With Flow, we can surface type errors even in files that don't have any type information other than the @flow directive, e.g. http://eng.uber.com/wp-content/uploads/2018/07/image4.png

To me that's a feature and not a bug. A good codebase would have --noImplicitAny enabled, which would catch this. Relying on usage of a function to know its types is fragile, the function should be the one declaring the types it uses so that callers can adapt to changes, not the other way around.
To build upon your comment, I really like the way Rust does things (they do it for coherence and major-minor versioning changes not breaking inference) - you declare types in functions (you have to) & structs, and everywhere else is optional (unless the type checker can't infer the type).
--noImplicitAny isn't quite equivalent though. What type inference provides is the ability to define the type of something somewhere and propagate that contract throughout a complex system such as a DI container.

The playground examples are just an oversimplication to illustrate the core difference between TS and Flow, but the screenshot gives a better idea of how it actually plays out in practice. In our case, we tie the type to the DI token and a plugin receives something that is guaranteed to be of that type.

This means someone migrating doesn't need to explicitly add types to their code, but can still get better gradual type coverage than `any` or the break-the-world `--noImplicitAny` flag.

I can totally see an argument for that if you need gradual type coverage, which I guess is needed on large code bases. I have only worked on smallish ones of a few thousand lines of code, and it took maybe an hour to type everything, although most of it was really fun and exciting :) but in cases where that's not realistic, I could see using Flow to help transition.
Does this inference work across files?
Yes, with some caveats. If you're `export`ing something as a package, you need to expose its types so that the consumer knows what its signature looks like. Once that is done, calling a function that was defined in another package will get type inference, as seen in the screenshot I posted.
Yeh those small bugs are very frustrating. I wish it was written in Javascript too.

A big issue IMHO is Ocaml. FP heads usually hate JS, and they cannot dogfood Flow.

All the little issues feel like the devs don't use it enough to know the pain.

They aren’t the same though. Flow’s type system is nominal, typescript’s is structural, which is a huge language difference.
Are they though? As a TypeScript user with very little Flow experience it seems like they are about the same:

https://flow.org/en/docs/lang/nominal-structural/

"For example, Flow uses structural typing for objects and functions, but nominal typing for classes." This statement also applies to TS.

Flow does have nominally typed Opaque Type Aliases[1], which are essentially newtypes from what I've gathered. However, you can build similar zero-cost newtypes in TypeScript using union types, casting and "unique symbol"[2].

[1] https://flow.org/en/docs/types/opaque-types/

[2] https://github.com/Microsoft/TypeScript/issues/4895#issuecom...

TypeScript seems to do structural typing for classes too: https://www.typescriptlang.org/play/#src=class%20Foo%20%7B%0...
i thought nominal typing was only for the classes?
That's true. Both Flow and TypeScript generally uses structural typing, but flow also has nominal typing for classes.
But Typescript is a language on its own. It claims to be a superset of JavaScript, but includes JS features that aren’t even certain to end up in JS (decorators). And their import system... Whereas Flow is proper JS. It’s just so... nice!
That's not true. TypeScript spec is just the latest JavaScript spec. Decorators are a JavaScript (TC39 stage 2) proposal, and TypeScript only uses them if you use --experimentalDecorators. And TypeScript uses the ECMAScript module system. Whatever other features you think TypeScript has that aren't "proper JS" probably are either already JS, or are late-stage TC39 proposals.
> And TypeScript uses the ECMAScript module system.

Erm, I was thinking of a discussion like the one over here:

https://github.com/Microsoft/TypeScript-React-Starter/issues...

Q: `import React from "react";` breaks in Typescript

A: have you tried `import * as React from 'react';`

Me: Golly!

> Decorators are a JavaScript (TC39 stage 2) proposal, and TypeScript only uses them if you use --experimentalDecorators.

Oh, didn’t know about the flag; I thought it's already a standard language feature now, what with all the Angular apps relying on it. As for decorators being a TC39 proposal, I am aware of that, but they have remained a proposal for quite a long time now, haven’t they (about 4 years now?), and I remember babel renaming the transformer for decorators to legacy-decorators-something, saying that the very semantics of decorators in JS is still debatable (some thought of them simply in terms of functions accepting a function and returning another function; some in more angular sense of injecting some properties into methods). I hope I am not completely misrepresenting the rationale here.

Pretty sure `import * as React from 'react';` is the correct EcmaScript syntax because React does not expose an ES module compatible `default` export. You're just used to it working anyway thanks to babel accepting CommonJS modules, but TypeScript is the one that actually follows the standard here.
> A: have you tried `import * as React from 'react';`

> Me: Golly!

You're fundamentally misrepresenting that whole issue, and if you'd read just two or three comments down you'd see that there is a better fix, and part of the problem is a behaviour that's not even related to the ECMAScript standard.

Yes, I missed that, thank you for the rebuke.
Ah right, the `import * as` problem. That was fixed with --allowSyntheticDefaultImports. According to the docs:

> Allow default imports from modules with no default export. This does not affect code emit, just typechecking.

https://www.typescriptlang.org/docs/handbook/compiler-option...

And I think you're right about decorators. They are an iffy concept in the context of JS semantics, and I personally avoid using them and try to avoid libraries that use them. That's probably why TS has them disabled by default and calls them "experimental". I like the concept of decorators in and of themselves, but they don't fit cleanly into the JS world, and I am looking forward to seeing how the JS/TS world innovates alternative "cleaner" solutions that fit better into the existing model!

We have high order functions in JS. Which are similar to decorators.
Similar, but harder to use safely and correctly in class methods using the new class syntax. There's more surface area for typos and other mismatch errors since you have to type the method names twice. See: https://mobx.js.org/best/decorators.html
Enums are not JavaScript, and I've never heard of an Enum stage X proposal.
Oh, you're right!

http://www.typescriptlang.org/play/#src=enum%20Direction%20%...

And yeah this could be valid JavaScript too, having nothing to do with types, but it's not in JS, only TS.

That said, it is a very cool and clever way to set k=v and v=k in an object at the same time!

What definition of "superset" are you using?