TypeScript vs. Flow

TypeScript and Flow are similar tools that focus on the same problem: JavaScript's lack of static types. Ultimately, they both exist to help you write correct code. Both TypeScript and Flow provide gradual static typing capabilities. They also use a similar syntax for type annotations and declaration files.

Backed by Microsoft and Facebook, both tools enjoy widespread usage among the developer community. When it comes to choosing between TypeScript and Flow, there are valid reasons for picking one over the other. The ecosystem you're working in usually has a big influence on your decision, as does your previous exposure to static type systems.

Deciding Between TypeScript and Flow

If you're working with Angular 2+, you might favor TypeScript because it's the dominant language used in the Angular community. If you're using React, on the other hand, you might prefer Flow because it easily integrates with Babel and other infrastructure you probably already have in place.

There are other factors you might take into account, too. In addition to focusing on static typing, TypeScript wants to provide great tooling and language services for autocompletion, code navigation, and refactoring. Flow, on the other hand, develops a deeper understanding of your code and even does interprocedural analyses.

All of the above are valid reasons for picking TypeScript or Flow over the other. However, I sometimes hear people advocate for Flow (and against TypeScript) because "it's just a type checker, while TypeScript is a separate language". That is not a valid reason, and here's why.

It's Not Just Type Checking

As soon as you're using a single type annotation, type alias, or some other Flow feature, you're no longer writing standard JavaScript. That is, you can no longer directly run that piece of code in the browser or another JavaScript environment like Node. Here's a simple Flow example, taken directly from the landing page of their website:

// @flow
function bar(x): string {
  return x.length;
bar('Hello, world!');

Try to run this piece of code in your browser console. It won't work! Instead, you'll get some error message like Unexpected token : because the parser complains once it encounters the return type annotation. In order to run this code successfully, the type annotations have to be removed.

This is where TypeScript and Flow differ: TypeScript implements both a type checker and a transpiler that emits plain JavaScript. Flow only does type checking and relies on Babel or flow-remove-types or some other tool to remove type annotations.

So, let me be clear about this: No matter if you're using TypeScript or Flow, you're not writing plain JavaScript. You're using non-standard language features. That way, both TypeScript and Flow should be considered to be languages different from JavaScript. TypeScript actively acknowledges this fact by using the .ts file extension rather than the standard .js one.

Putting Type Annotations in Comments

That said, there is a way to use Flow without writing non-standard JavaScript code. Type annotations can be placed within code comments and Flow will still recognize them. Here's the example from before:

// @flow
function bar(x) /* : string */ {
  return x.length;
bar('Hello, world!');

Now, this is valid JavaScript code that you can execute in every environment, no pre-processing necessary. However, I don't really like this approach because I think the additional syntactic noise makes it harder to read the code. Also, comments aren't a suitable place to host a type system.


Both TypeScript and Flow are great products. Both help you write correct code. You don't go wrong using either one, so pick the one that better suits your team's needs. However, please don't suggest that Flow isn't a separate language while TypeScript is — unless you're strictly putting type annotations in comments, you'll be writing non-standard JavaScript either way.