Use Flow to Check Your JavaScript Types
Tags: javascript, tutorial, webdev, beginners
Published: 2020-02-06 02:16:17

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

**Follow me on Twitter at https://twitter.com/AuMayeung**

**Many more articles at https://medium.com/@hohanga**

**Even more articles at http://thewebdev.info/**

Since JavaScript is a dynamically typed language, there’re going to be problems with variables and object properties having unexpected types. Also, some JavaScript type coercion rules are arbitrary. To make developing JavaScript apps easier, Facebook made extensions to JavaScript to add type annotations and type checking to the language.

* * *

Adding Flow to a Project
========================

The language, which consists of Facebook’s extension to JavaScript along with the original JavaScript language, is called Flow.

We can easily use it in a new project. To add it globally, we just install Yarn and run:

```bash
yarn add --dev @babel/core @babel/cli @babel/preset-flow
```

Then, we create a `.babelrc` file and add the following:

```json
{  
  "presets": ["@babel/preset-flow"]  
}
```

Then we can build and run the code:

```bash
yarn run babel src -- -d lib/
```

The command can be added to the `package.json` file as follows:

```json
{
  "name": "project-name",
  "main": "lib/index.js",
  "scripts": {
    "build": "babel src/ -d lib/"
  }
}
```

We can also add it per project by running `yarn add --dev flow-bin` in our project, adding Flow as a development dependency for the project. Then we can run the `flow` command: `yarn run flow` (You may have to run `yarn run flow init` if you haven’t run it before).

* * *

Adding Flow Code to for Type Checking
=====================================

Now that Flow is installed, we can add type annotations to our code to let Flow do type checking.

The simplest way to do this is to add type annotations after a variable to indicate its type:

```javascript
// @flow  
let x: number = 1;
```

Notice that we have to add `// @flow` over our code to enable Flow to do the type checking of our code.

Also, we can add type annotations to function parameters:

```javascript
// @flow  
function cube(x: number): number {  
  return x**3;  
}
```

Then when we write: `cube('');` we get the following error:

```
[Flow] Cannot call `cube` with empty string bound to `x` because string [1] is incompatible with number [2].
```

This is because we passed in a string to a function that expects a number.

If we pass in a number, it should run:

```javascript
cube(2);
```

* * *

Basic Types
===========

Flow has its own type annotations for various data types that we’ll encounter in JavaScript.

Like JavaScript, it has various primitive data types. JavaScript has the following primitive types:

*   Booleans
*   Strings
*   Numbers
*   `null`
*   `undefined` (`void` in Flow types)
*   Symbols (since ES6, but not yet supported in Flow)

They’re available as literals or constructed with wrapper constructor or functions:

```javascript
//literals
true;
"abc";
1;
null;
undefined;

// constructors
new Boolean(false);
new String("abc");
new Number(1);
// factory function
Symbol("abc");
```

Literal values have type names in lower case. Objects of types that are created with constructors have type names in upper case. For example, we can have:

```javascript
// literals
x: number

// constructor objects
x: Number
```

Booleans
--------

Booleans can be either `true` or `false` . We can write:

```javascript
// @flow
function boo(val: boolean) {
  
}
boo(true);
boo(2);
```

`boo(2);` will give us the follwing error:

```
[Flow] Cannot call `boo` with `2` bound to `val` because number [1] is incompatible with boolean [2].
```

JavaScript converts objects to boolean when it’s needed. For example, it will convert it inside `if` statements or equality statements when we compare to booleans.

In JavaScript, we can write this:

```javascript
if (1) {}
```

This is because it has truthy and falsy values. Falsy values are converted to `false` when conversion to boolean is done. The following values are falsy:

*   0
*   `undefined`
*   `null`
*   `NaN`
*   empty string
*   `false`

Everything else is truthy.

With Flow, we have to explicitly pass in boolean values if we have a parameter or variable of type `boolean` or `Boolean`. `boolean` and `Boolean` types aren’t interchangeable with Flow. Given that we have:

```javascript
// @flow
function boo(val: boolean) {
  
}
```

If we write `boo(new Boolean(true));` we’ll get the following error:

```
Cannot call `boo` with `new Boolean(...)` bound to `val` because `Boolean` [1] is incompatible with boolean [2].
```

Numbers
-------

JavaScript has only one type of number. It can be floating-point or an integer.

Flow has both the `number` and `Number` types. The `number` type is for numeric literals and the `Number` type is the wrapper object.

For example, we can write:

```javascript
let x: number = 1;
```

Or we can write:

```javascript
let x: Number = new Number(1);
```

However, we can’t write:

```javascript
let x: number = new Number(1);
```

The code above will get us the following error:

```
[Flow] Cannot assign `new Number(...)` to `x` because `Number` [1] is incompatible with number [2].
```

We also can’t write:

```javascript
let x: Number = 1;
```

This will give us the following error:

```
[Flow] Cannot assign `1` to `x` because number [1] is incompatible with `Number` [2].
```

Strings
-------

Flow has the `string` and `String` types for the literal and wrapper object respectively.

It works like other primitive types. So we can write:

```javascript
let x: string = 'abc';
```

Or we can write:

```javascript
let x: String = new String('abc');
```

But we can’t flip the literal and wrapper object assignments.

Flow will only accept concatenation of strings and other strings or numbers. This means the following will work:

```javascript
"foo" + "bar";  
"foo" + 1;
```

We can also concatenate a string literal with a wrapper object string. For example, we can write:

```javascript
"foo" + String('abc');
```

However, we can’t concatenate a string with a String created with the String constructor. So the following will give us an error:

```javascript
"foo" + new String('abc');
```

Concatenating string with any other types will get us errors.

`null` and `void`
-----------------

Flow has the `null` type to represent the `null` value, and `void` to represent the `undefined` value.

So the following will work:

```javascript
let x: null = null;  
let y: void = undefined;
```

Nothing else can be assigned to these types. This is the same for function parameters.

Facebook created Flow to let us check the types of data in our code for correctness. It prevents unexpected type assignments to variables and function parameters.

For primitive types, it has separate types for objects created with constructors for primitive objects and literal. For example, `string` is for the string literal and `String` is for strings created with `new String(...)` .

It also has the `null` and `void` types for `null` and `undefined` respectively.