Hacker News new | ask | show | jobs
by mirekrusin 1362 days ago
We need:

- exact object type

- match expression

flow is still better at:

- OO - nominal typing for classes, conforming to liskov substitution principles

- first class opaque types

- first class exact object types

- better flow based inference

- comment types - no extra dsl, full access to the language, so simple, so powerfull for the times you don't want transpilation phase

- [edit] spread types map to spread in runtime

4 comments

Flow feels almost like the Betamax to Typescript's VHS - Flow is better technically in many ways (in addition to the things you mention, I miss being able to spread the properties of one type into another, rather than having to inherit from an interface), but in practice, in terms of engineering cost, it's so much more expensive that it's hard to justify using it.

Flow's team have made it clear [0] that they don't care about usage outside internal Facebook projects, so since Facebook (from what I hear) uses few external JS dependencies, support for library types is terrible - there's no practical way for library developers to ship Flow types with their library. The third-party flow-typed repository helps somewhat, but relatively few libraries are covered there, so in practice you'll need to write your own typedefs for most libraries you want covered.

When I worked in a Flow codebase, I enjoyed writing Flow types for things, but it was only ever fun in a sudoku-puzzle-solving, Zachtronics-game kind of way. The tools provided were technically enough to express whatever you wanted, but it always took some lateral thinking. TS certainly allows for the same kind of type astronautery, but as a non-library app developer you never have to resort to that; you can always fall back to something slightly less strict that covers you from most real-world problems without the all-or-nothing strictness Flow mandates. In the end I was the last holdout on the team advocating for not migrating to TS. The migration went well and the team was more productive for it.

It's fun to think about an alternate universe where Facebook gave Flow the investment and community support it deserved, and today it's part of a beautiful React/Flux/Jest/Flow/Reason ecosystem (eventually leading to a complete takeover of the browser frontend by Ocaml). For real work, though, Typescript gets the job done.

[0] https://medium.com/flow-type/clarity-on-flows-direction-and-...

They messed up with contributions to flow-typed where they were not accepting partially done typings, ie. not having some kind of incubator. People would push stuff, others would fix it. In community run projects you need to focus on low friction, not perfectionism. That killed typing coverage while ts was growing like crazy. Typing coverage worked like magnet for ts vs flow decisions. So it killed flow in effect.
>I miss being able to spread the properties of one type into another, rather than having to inherit from an interface)

What would that achieve that intersection types don't already?

Spreads are ordered, and try to match the semantics of object spreads at runtime. Intersection types don't do that, they express that the type is both things at the same time. It is most obvious when dealing with types that have overlapping properties: [typescript with intersections](https://www.typescriptlang.org/play?#code/C4TwDgpgBAglC8UDeA...) [flow with spreads](https://flow.org/try/#0C4TwDgpgBAglC8UDeAfAUFTUBmB7XAXFAHYCu...).
They map onto same type as runtime spread, ie. order matters last one overwrites.
Pattern matching is actually being discussed in tc39 for JS as a whole (where TS reps are some of the champions, ofc): https://github.com/tc39/proposal-pattern-matching

The specifics of the proposal will likely shift a bit since it's still stage 1 (2?).

I don’t understand the benefit of nominal typing when structural typing is available?
The idea is that two types with the same structure aren't always the same thing.

This is easily solved by a tagged type in TS [1], though a bit of syntactic sugar over it would be nice.

[1]: https://kubyshkin.name/posts/newtype-in-typescript/

In practice I’m very happy with structural types. It provides all the safety I could wish for and slots in well with the underlying language and broader ecosystem.

Though I do miss an easy way to create something like a type Email of string, as it conforms to a set of rules. But that’s a small price to pay.

Flow has structural typing on types and nominal on classes with correct inheritance semantics, which simply makes sense.

For making Email type distinct from string, you want opaque type (first class in flow) which you can emulate as tagged type in ts.

Oh! Interesting. I was unaware of Flow’s details. Though I never program in an OOP style so I wouldn’t have noticed those nuances anyway.

I know of TS’ opaque types, but it always feels dirty. So here I am, relying on named params instead.

Tagging doesn't solve inheritance problems - object oriented inheritance needs to follow liskov substitution principles, support variance correctly.

Tagging is good for making sum types out of union types, but that's not enough for class inheritance.

Flow does it better by having first class opaque type aliases btw (and having nominal types with oo inheritance support on classes of course).

You can't use `instanceof` ie. for your error types, actually every time you use class that extends something - it'll not be typed correctly. Basically nothing OO/class/inheritance related is typed correctly. Flow does it correctly.
You can’t type generators properly a la redux-saga