Flow is a typed dialect of JavaScript.
It looks like TypeScript now. Plus component / renders / match. And still safer.
Familiar syntax
Is it Flow or TypeScript? You can't tell. Flow has keyof, readonly props, unknown, indexed access types T[K], and extends generic bounds. Plus conditional types, mapped types, and type guards. More TS-compatible syntax
1type User = {2 readonly name: string,3 readonly age: number,4 readonly metadata: unknown,5};6function get<K extends keyof User>(user: User, key: K): User[K] {7 return user[key];8}9declare const user: User;10const age: number = get(user, 'age');First-class React
component and renders are built into Flow's syntax. Props are named parameters, typed inline with defaults, so there's no props object to annotate or destructure. Only components that render Header can flow into a renders Header prop: design-system composition rules become type errors instead of bugs caught in review. More on component and renders
1import * as React from 'react';2
3component Header(text: string = "Title") { return <h1>{text}</h1> }4component Footer() { return <footer /> }5
6component Layout(header: renders Header) {7 return <div>{header}</div>;8}9
10<Layout header={<Header />} />; // OK11<Layout header={<Footer />} />; // ERROR: doesn't render HeaderPattern matching with match
match is both an expression (shown here) and a statement: a safer switch with no fall-through. It's exhaustively checked, with structural patterns that destructure as they match. Forget a case, like 'remove', and match flags it and tells you what to add. More on match
1type Action = {type: 'add', text: string}2 | {type: 'toggle', id: string}3 | {type: 'remove', id: string};4declare const action: Action;5
6const description = match (action) { // ERROR: 'remove' missing7 {type: 'add', const text} => `Add: ${text}`,8 {type: 'toggle', const id} => `Toggle ${id}`,9};Exact objects by default
Object types in Flow are exact by default. TypeScript only catches extras on direct object-literal assignment, so sample: "free" slips through once the object goes through a variable. Flow catches it at the assignment, before the crash. More on object exactness
1type Prices = {apple: number, banana: number};2const items = {apple: 1.5, banana: 0.5, sample: "free"};3
4const prices: Prices = items; // ERROR: extra property `sample`5
6Object.values(prices).map(price =>7 `${price.toFixed(2)}`, // Runtime crash! `toFixed` on "free"8);Safety by default
Extracting a method from a class instance loses its this binding. TypeScript lets the extraction through; tick() then crashes inside increment because this is undefined. Flow rejects the extraction. More differences from TypeScript
1class Counter {2 count: number = 0;3 increment(): number {4 return ++this.count;5 }6}7const counter = new Counter();8const tick = counter.increment; // ERROR: unsafe method extraction9tick(); // Runtime crash! Invalid `this` inside `increment`Use Flow in your project
Used in production at Meta across millions of files of JavaScript and React.