
Flow and TypeScript - msoad
https://engineering.tumblr.com/post/165261504692/flow-and-typescript
======
esamatti
It's worth noting that with upcoming Babel 7 it is possible to strip
Typescript types like with Flow and use it just as a typechecker/linter [1].
This means following things:

\- You don't need ts-loader/at-loader with Webpack anymore. You'll lose
typechecking during webpack build but you can run it as separate step. Your
editor will show them as usual still.

\- You can use all the Babel plugins with Typescript without running two
compilers (should speed things up)

\- Should add first class support for React Native as it uses Babel (or at
least no more 2-step builds)

[1]: [http://babeljs.io/blog/2017/09/12/planning-
for-7.0#typescrip...](http://babeljs.io/blog/2017/09/12/planning-
for-7.0#typescript)

EDIT: For the curious here's my build configuration with Webpack demoing this
with extra plugins
[https://gist.github.com/epeli/bb8ae386f9dbb2a4ae2159e1f265fd...](https://gist.github.com/epeli/bb8ae386f9dbb2a4ae2159e1f265fd56)

~~~
msoad
Some features like enums are not supported and why on the earth you want to
lose the type checking?

~~~
esamatti
Faster and simpler builds setups. And you don't really lose it as your editor
will report the type errors. Flow is used like this all the time.

Tried this on a project of mine. Enums seem to work fine for me.

EDIT: There are some issues with enums indeed
[https://github.com/babel/babel/tree/master/packages/babel-
pl...](https://github.com/babel/babel/tree/master/packages/babel-plugin-
transform-typescript)

~~~
stupidcar
Wouldn't the simpler build setup be to use TypeScript only for compilation?
Why would you want to use Babel as well?

~~~
1_player
From what I understand, TypeScript doesn't do any transpiling, so if you want
to use ES6/2017 features, you're going to need Babel.

(I haven't used TypeScript yet, so I might be wrong)

~~~
pafje
Typescript has always transpiled to ES5 (by default it transpiles to ES3
actually). See: [https://stackoverflow.com/questions/41173215/does-
typescript...](https://stackoverflow.com/questions/41173215/does-typescript-
transpilation-handle-transpiling-es6-to-es5)

The only counter-example that I know of is that async/await were initially
only supported when transpiling to ES6, but this is not true since at least
2.2
([https://github.com/Microsoft/TypeScript/issues/5210](https://github.com/Microsoft/TypeScript/issues/5210)).

------
pcx
We faced a similar situation in our project and went with Flow instead. We
found a TS + Webpack setup too unreliable. There are couple of popular Webpack
loaders (ts-loader and at-loader), and both kept crashing the Node process
every other build. Build times were pretty high. We could not find any
documentation on how to fix these problems, except for a few open GitHub
issues.

We then tried Flow. Oh dear god, has it been a blessing.

Pros:

* It's seamless to integrate with Webpack, ESLint & Babel.

* It's crazy fast

* Has great support for React

* Fits in perfectly with Redux

* Dead easy for beginners to learn

* Has an amazing Type system. My major experience with types has been Java, and Flowtype just blew my mind with - non-nullable types, subtyping and type refining.

* Documentation is great

* Community is very active

Cons:

* About 1/3rd of the time error messages are not intuitive. But nothing you can not figure out. And it's getting better.

~~~
jinder
What about flow gives it better support for React than TS (other than it being
built into the CLI)? Why does it fit more perfectly with Redux than TS? Why is
it easier to learn than TS? Why does it have a more amazing type system than
TS?

~~~
pcx
As I mentioned we couldn't get TS + Webpack to work properly. I am not dishing
TS, I just couldn't evaluate it all that well. To expand more on your points:

\- Flow has more & better type definitions for React than TS. I think it's
because a lot more React devs use/develop Flow and also both are FB projects.

\- For our Redux + Flow setup, we export an ActionCreator type that is a union
of all action creators we've defined. This union gets refined by the switch
statements in reducers, allowing us access to well typed action creators in
reducers, without having to deal with import/export of individual types.

\- The docs are pretty good. Several of my colleagues are new to static
typing, and have picked Flow up easily because of the docs. I also heard some
interest in providing video courses like Egghead.

\- Flow has an amazing type system compared to Java. Except for enums though.
Java Enums are much much better.

~~~
mediumdeviation
Flow bakes React libdefs right into the binary
[https://github.com/facebook/flow/blob/master/lib/react.js](https://github.com/facebook/flow/blob/master/lib/react.js)
\- so yes, Flow damn well have good React support, because the React libdef is
given the same level of importance as Node and DOM APIs.

Of course it also means you can't upgrade React without upgrading Flow, and
you can't target a specific (older) version of React without downgrading Flow.

------
vosper
I enjoyed seeing a side-by-side comparison of some differences between the two
systems. It seems to mix tooling support with language features, but I think
that's fair, because good tooling is essential. It would be nice to see some
more examples, but clearly some effort went into this evaluation.

I'm surprised the author thinks that Flow is more popular amongst the React
community than Typescript. I hardly ever hear about Flow, and I work with
React and follow it's development. I've been gradually concluding that
Typescript has won in terms of future-of-frontend, so I'd be curious to know
if people disagree.

~~~
spraak
Yeah, the impression that I get is that TS has won as well. Initially it
really offered a lot more than Flow, e.g. things like Definitely Typed, and I
think that's become a feedback loop (i.e. more people are interested in TS
because it already has a bigger community and more to offer, and thus it has
as bigger community and more to offer...)

~~~
addicted
I'm sure the fact that flow is considered more tired to react while typescript
is considered more agnostic helps as well (I've not explored flow so I don't
know whether it is tied to react or not but I do think that's the impression).

~~~
ng12
I don't think Flow is tied to React at all, except that the default create-
react-app includes it as an option.

~~~
baxuz
It's very tied to the react / facebook ecosystem.

Nuclide for atom was the official release by facebook for supporting flow +
react, and now you have Atom-IDE which is optimized for react + immutable.js +
flow.

Plus the facebook guys are avoiding VScode like the plague and focusing
entirely on Atom. Which now also comes with the BSD+ licence.

~~~
chillee
"Plus the facebook guys are avoiding VScode like the plague" Not true.

------
voidr
The goal of Flow was apparently to be able to add types to some parts of the
code while leaving the rest of it unchanged, this to me was confusing, because
at that time, you were already able to do that with TypeScript.

Over time the argument in favour of Flow became the following: it has a
"sound" type system, which means it produces better results in some extreme
cases where TypeScript fumbles. I didn't seem to ever hit those corner cases,
I just enjoyed the fact that TypeScript had a more robust type system.

Next argument was: Flow is just a linter that strips out the type annotations.
Most projects that use Flow use a transpiler, which renders the linter
argument moot.

As of today, I don't know of anything that you can do with Flow and cannot do
with TypeScript, the reverse is not true though.

Unless I'm missing something, it seems that Flow's existence is based on
tribalism rather than rationality, the Angular team realised that if there is
already a project out there that covers 99% of their needs, it might be better
to just work with the project instead of reinventing the wheel, Facebook seems
to have been ignorant of that. Facebook developers seem to have a tendency to
just re-invent the wheel instead of collaborating, see Yarn, I'm not saying
that they are wrong in doing so, there is a chance that they might be on the
right, however I don't feel that is the case when it comes to TypeScript.

~~~
stupidcar
> Unless I'm missing something, it seems that Flow's existence is based on
> tribalism rather than rationality

This is my impression as well. The Facebook employees I see on Twitter seem
like super-smart people, but unfortunately they also seem to have a degree of
arrogance and aggressiveness about how their tech is superior to everything
else, which they often express by trash-talking the "competition".

In fact, a lot of the Flow / React / Yarn, etc. community seems vaguely cult-
like, with a cabal of Facebook/ex-Facebook employees as its leaders, and an
implicit (or explicit) contempt for anyone too stupid to recognise their
righteousness. That alone makes uncomfortable enough to avoid using any of
these projects when I have the option not to.

------
bluepnume
I'm a huge Flow fan, and picked it over TypeScript because at the time I
didn't like the idea of:

\- Switching everything to .ts and .tsx files

\- Switching a lot of tooling (TypeScript's built-in ES6 transpiler instead of
Babel, tslint instead of eslint, etc.)

\- At the time, TypeScript's types were nullable, Flow's were non-nullable,
which makes a huge difference to me

\- Given that TypeScript is a transpiler along with a static type-checker,
it's not always easy to tell which features are going to have build-time vs
run-time effects (e.g. private properties, property decorators)

That said, some of the errors from Flow can be incredibly confusing, and even
with the latest versions I feel like there's improvement which needs to be
made here. This (in my view) is the number one thing it needs to drive
adoption.

~~~
bcherny
I went through a similar process and chose TS > Flow.

\- Renaming to .ts and .tsx is nicer than adding comments, because it
integrates better with tooling (compile all files that end with .ts) and it's
easier to see at a glance what's ported

\- You can always compile TS to ES2018 and run that through Babel, if you
like. TSLint -> ESLint is indeed a change, though you can continue to use most
of ESLint for TS [0]

\- As a rule, TS is compile time only. There are a few exceptions, but that's
almost always the case.

For me the advantages of TS are:

\- Huge library of community written typings for JS libs

\- Mapped types

\- Full support for literal types

\- Read only types

That said, I really like Flow's co/contravariance annotations, and the
corresponding $Supertype and $Subtype functions. That, and nominal typing can
be really convenient (coming to TS soon, hopefully).

[0] [https://github.com/eslint/typescript-eslint-
parser](https://github.com/eslint/typescript-eslint-parser)

~~~
klibertp
> That, and nominal typing can be really convenient (coming to TS soon,
> hopefully).

I think you meant structural typing? TS was always nominally typed. I searched
for a bit and it looks like TS also supports structural typing with explicit
interfaces, and I think Flow tries to infer such types? I don't use either
one, so I'm not sure about the details.

~~~
cowmoo728
TS is structurally typed. You declare the fields you expect on a type or
interface, and as long as an object has at least those fields, it will
typecheck. Nominal typing would mean that you could declare type A and type B
with identical fields, but if something is declared as A, it cannot be used in
place of B.

TS has a strange workaround to get nominal typing for now:

[https://basarat.gitbooks.io/typescript/docs/tips/nominalTypi...](https://basarat.gitbooks.io/typescript/docs/tips/nominalTyping.html)

~~~
klibertp
That's interesting - I'm almost sure last time I checked (possibly a couple
years back) TS used nominal typing. Do you know if this changed at some point,
or is it just my memory being bad?

~~~
RyanCavanaugh
TypeScript has used structural typing since the beginning. Classes used to be
nominal, but changed to structural (except for classes with private fields) at
some point.

~~~
klibertp
> Classes used to be nominal, but changed to structural

Ah, ok, makes sense. I think I was last looking at TS around version 1.1 or
something like that. Thanks!

------
ng12
Flow's tooling was a nightmare last I tried to use it. It seems custom built
for a very specific purpose -- incrementally adding types to an existing
legacy codebase. Typescript's tooling works seamlessly with webpack/babel/etc.

~~~
lasfter
npm install --save-dev flow-bin babel-preset-flow, add "flow" to the presets
in .babelrc and it just works, at least for my projects.

~~~
gcommer
A much more typical experience is to do those 2 steps, and then spend a bunch
of time digging through github issues to find the right ignore/suppression
incantations to add to your .flowconfig so that your dependencies (including
all their transitive deps...) don't break your typechecking. Admittedly this
gets easier once you've done it before and know a few reference .flowconfigs
to copy/paste like React[1] or babel[2], etc. But this shouldn't be necessary
at all. It's been an open issue for 2 years [3].

Less important, but you also have to add /* @flow */ to the top of every
single source file. Sure its handy sometimes for existing projects, but it
makes little sense for new ones and has also been an issue for years[4].

[1]:
[https://github.com/facebook/react/blob/65b9ad94aaf62eb61b7b3...](https://github.com/facebook/react/blob/65b9ad94aaf62eb61b7b3888362c2e7c0b06697a/.flowconfig)
[2]:
[https://github.com/babel/babel/blob/634c750558e5ce149b879b66...](https://github.com/babel/babel/blob/634c750558e5ce149b879b66888d5ffd41865cab/.flowconfig)
[3]:
[https://github.com/facebook/flow/issues/869](https://github.com/facebook/flow/issues/869)
[4]:
[https://github.com/facebook/flow/issues/284](https://github.com/facebook/flow/issues/284)

~~~
whatever_dude
This has been my experience as well. I used to think configuring tsconfig was
more work than I wanted, until I started using Flow in a project and had to
babysit .flowconfig. It's hell and adding any dependency can break it in
confusing ways.

------
boubiyeah
I tried Flow 3 times and was always severely disappointed. It's just not as
good as TS if you care about type soundness (both are unsound, but Flow just
tries too hard to make compromises for mixed codebases) I always found tons of
type-checking bugs in Flow, which is a deal breaker for what we're doing (100%
type coverage)

~~~
yawaramin
Have you tried [https://reasonml.github.io/](https://reasonml.github.io/) ?

~~~
boubiyeah
Only a bit. I really like ML languages. The issue is that the ecosystem is
still in its infancy.

~~~
yawaramin
I'd recommend keeping an eye on it; it's growing very fast.

------
wakeywakeywakey
After using both, TypeScript feels more natural and clean. Flow adds too many
syntax deviations that I generally dislike.

TypeScript works amazingly well with React. Also, it's great only having 1-2
build dependencies rather than 10+ Babel plugins.

------
cies
Nice article. A little meta-study and then some practical usage compared.

Facebook is also working on ReasonML (a new front-end and some tooling for
OCaml/BuckleScript) that compiles to JS and has strong typing. Stronger than
either TS of Flow has.

I think in the long run ReasonML is a better approach: the underlying language
(OCaml) is carefully designed, where JS seemed to have "happened".

Other options that have even stronger typing are Elm, PureScript and
Haskell/GHCJS.

Here's a great article describing all the promising projects in
functional/strongtypes front-end land:

[https://medium.com/@saurabhnanda/benchmarks-fp-languages-
lib...](https://medium.com/@saurabhnanda/benchmarks-fp-languages-libraries-
for-front-end-development-a11af0542f7e)

------
enugu
Integration with a contract system like Clojure Spec is one of the best
features still missing in current type systems. Having that would get best of
the both worlds and allow better interaction with untyped code. Racket has
this currently.

I like Typescript. But wish it had exact types like Flow. This leads to not
being able to type a simple Algebraic Data Type with complete precision.

I think the reasoning given on the github page for not having exact
types(involving how it plays with intersection types and union types) has a
bug. One _can_ assign T & U to T even when T is exact(exactness of T ensures U
wont introduce extra properties), and assigning T to T | U should be fine when
U is exact(For a user to determine if a T|U value is T or U, they will have to
check whether a property in T exists, not U).

But this is a very small issue.

------
fauigerzigerk
I'm a bit skeptical of type declarations that are not formally linked to a
specific version of the code they describe and cannot be considered to be
commitments made by the author of the code.

It's yet another layer of organization and complexity that we need to keep
track of on an already incredibly convoluted platform.

Neither TypeScript nor Flow force you to use third party type declarations,
but using them seems to be strongly encouraged.

We'll see how problematic this issue turns out to be as these ecosystems
evolve.

~~~
seanwilson
What are your options though? Don't use third party code? Use third party code
with no types along with your typed code? The unofficial types might have some
problems (which I've yet to be bitten with yet) but it's much better than
nothing.

~~~
fauigerzigerk
I'm not convinced it's necessarily better than nothing. Introducing this whole
new layer of complexity, potential breakage and maintainance issues is a
trade-off. It could go either way depending on many factors.

Another option is to use a proper statically typed language where that is
feasible.

Choosing between TypeScript and Flow I would keep an eye on how each of these
ecosystems deals with the issue of third party type declarations and
versioning.

And if one of these languages gains support by library authors so that we
don't need third party types, that would be a strong argument in favor of that
language for me.

~~~
frou_dh
To get the benefit of static typing in the browser, it seems more strategic to
use something that's actually a meaningful departure from JS (Elm, Scala.js,
PureScript, ...) rather than JS as viewed in a warped mirror.

You don't want to be fighting to change the fundamental nature of something
while being crammed in the trench with it.

------
CamTin
Am I missing something with compile-to-javascript languages, or does this kind
of heavyweight tooling and build system preclude most on-the-fly repl/console
use for development? I'm far from a professional webdev, but have been
attacking it recently with the goal of shortening my idea-to-implementation
time for side/portfolio projects (I'm tangentially in ops at a tech company
now, but want to move into programming).

Coming from a lisp background, the immediacy of the JS console in the browser
seemed like a huge win, and I can't really imagine javascript-heavy webdev
without using [https://github.com/skeeto/skewer-
mode](https://github.com/skeeto/skewer-mode) or something similar, or at the
very least heavy use of the browser's javascript console.

Don't you give up a lot of efficiency/speed when you compile to JS instead of
using JS directly? Or do I misunderstand the trade-off and the benefits of
static typing are enough that it's acceptable to have a separate build step
after every change, like you're a C++ programmer?

~~~
winterlight
I don't know about Flow, but in Typescript you can still fire up a REPL and
play around. The difference is that the typechecker validates every command
you run. This is enough for small experiences, e.g., when you want to validate
an algorithm. But yes, in the case you want to rerun your application to test
your changes, the feedback cycle is a bit longer. But I find acceptable
considering that static-typing makes refactoring significantly easier and less
risky, which is important when working on large projects.

------
bernadus_edwin
Is this normal if flow show many error list from node_modules library. How to
filter ignore from library? Flow - reactnative - vscode

------
int_19h
Given how close these two things are, I wish the field would settle on one -
either one, really - so that we could embrace its ecosystem, and move on with
more and better libraries, tooling etc for the winner.

~~~
invaliduser
I don't think this will happen, because Typescript now has a very large user
base, and Facebook will stick to Flow.

However, I don't think flow is going to survive React, because it's only used
there and internally at Facebook, while Typescript is used successfully with
React, Angular, and basically everywhere people need typechecking outside of
React (Typescript has definition files for most libraries with significant
users)

~~~
Matthias247
One other interesting thing is that Facebook is even internally cannibalizing
itself, by developing and promoting both Flow and ReasonML as a way to develop
web apps.

From the outside it really seems there are 3 ecosystems, a large one
(typescript) und 2 others (Flow and ReasonML) that are mainly used for parts
of facebook.

