Skip to content
This repository has been archived by the owner on May 25, 2020. It is now read-only.

Latest commit

 

History

History
200 lines (140 loc) · 4.93 KB

flow.md

File metadata and controls

200 lines (140 loc) · 4.93 KB

Flow

Resources

Introduction

Flow is a static type checker that helps you write code with fewer bugs. Flow allows you to incrementally add types to your JavaScript code to perform type-checking.

You need to tell Flow which files to type-check, for this you add a // @flow comment at the top of the file.

Once you’ve declared a file to check, you can use the Flow syntax in that file to define types.

CLI Commands

  • yarn run flow will type-check the project based on the .flowconfig file.
  • yarn run update-types updates the Library Definitions.

Library definitions (AKA "libdefs") are files that inform flow of the type signature of third-party packages. They are .js files placed in the flow-typed directory.

flow-typed is used to install pre-existing libdefs, it is analogous to TypeScript's DefinitelyTyped.

Flow syntax

Primitives

You can add types for Javascript primitives, as well as Array, Object and other constructs:

const isLogged: boolean = false;

const userId: number = 1234;

const userName: string = 'Mark';

const data: null = null;

const undefined: void = null;

const arrayOfNumbers: Array<number> = [1, 2, 3];

const userData: { name: string, id: number } = {
  name: 'Mark',
  number: 1234,
}

const sum = (a: number, b: number): number => {
  return a + b;
}

Type Alias

One of the most useful features is type aliasing. They allow you to use existing types to create new types:

type Transaction = {
  id: number,
  description: string,
  value: number,
};

Generics

Generics allow you to abstract over types:

type GenericObject<T> = { key: T };

const numberObject: GenericObject<number> = { key: 1234 };
const stringObject: GenericObject<string> = { key: "text" };

Maybe

A question mark is used to represent Maybe types, they represent a potentially null or undefined value:

const stringOrNull: ?string = null;

There are other useful type definitions like Union Types and Utility Types, you can find them in the documentation.

React Integration

Flow has very good support for React. This sections explains some common patterns to type React code.

React Components

The React.Component class takes two type arguments, Props and State. You can use them as replacement of PropTypes, which was the recommended way to type check React components.

type Props = {
  foo: number,
};

type State = {
  bar: number,
};

class MyComponent extends React.Component<Props, State> {
  state = {
    bar: 42,
  };
 
  render() {
    return this.props.foo + this.state.bar;
  }
}

If the component doesn't have state, you can just pass <Props>.

Flow includes utility types which can be useful to type complex React pattern. The most important ones are:

  • React.Node, represents any value that can be rendered by React. It can be a string, number, boolean, null, or React element.
  • React.ComponentType<Props>, is the type of any class component or stateless function component. This is useful as an input type for Higher Order Functions.
  • React.Element<Type>, is the type of a React element.

Note: React must be imported as a namespace (import * as React from 'react'), this way you get access to React's utility types.

Stateless functional components are typed like regular functions:

type Props = {
  bar: string,
};

function MyComponent(props: Props) {
  return <div>{props.bar}</div>;
}

Redux state

Typing Redux state works like typing any other object in Flow:

type State = {
  users: Array<{
    id: string
    name: string,
  }>,
  activeUserID: string,
  // ...
};

Redux state is meant to be immutable: you should creating a new state object instead of changing properties on it. You can enforce it with Flow by making every property "read-only" using "covariant" properties like this:

type State = {
  +users: Array<{
    +id: string
    +name: string,
  }>,
  +activeUserID: string,
  // ...
};

Redux actions

You can use disjoint unions to type all actions supported by a reducer:

type FooAction = { type: "FOO", foo: number };
type BarAction = { type: "BAR", bar: boolean };

type Action =
  | FooAction
  | BarAction;

This way you can use the individual action types to type action creators, and the general Action type to type the reducer.

Redux reducers

Reducers take and receive the state and actions we have previously defined:

function reducer(state: State, action: Action): State {
  // ...
}

Check the documentation for more detailed information.