| While the type annotation syntax between Flow and Typescript are mostly identical (this is intentional), there are a bunch of differences between them: * TypeScript allows unsound casting, Flow doesn't. These casts are very practical, as you might know more than the analyzer. Flow takes a stricter position here, which is a theme. * Function are bivariant w.r.t. their parameters (which is unsound) in TypeScript, but contravariant in Flow. Again, this is an intentional, practical choice, but Flow emphasizes soundness. * TypeScript asks users to add annotations in scenarios where Flow will infer types. TypeScript will infer any (there is a "no implicit any" option). * Classes in Flow are nominal (interfaces are structural). Classes are structural in TypeScript. * Flow adds no additional runtime syntax to JavaScript; TypeScript does (enums, for example). Flow does support some ES2016 features (async/await, object spread), but generally holds off on experimental features (stage < 2). * Flow has a couple interesting features absent in TypeScript, like disjoint unions. I suspect/hope both systems will converge on useful features like this. * TypeScript treats null as a bottom type, but Flow uses explicit "maybe types." |
The two real pain points (among those you mentioned) of TypeScript are bivariant function parameters and structural classes, since they lead to potentially unsound code that compiles.