JavaScript Type Checking with Flow — Variables and Functions
Tags: beginners, tutorial, webdev, javascript
Published: 2020-02-04 02:25:41

**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/**

Flow is a type checker made by Facebook for checking JavaScript data types. It has many built-in data types we can use to annotate the types of variables and function parameters.

In this article, we’ll look at data types supported by Flow for type checking, including variables and basic properties of functions.

Variable Types
==============

Just like in JavaScript, we can declare variables and constants with Flow with the `let`, `var`, and `const` keywords respectively.

`let` and `var` are used to declare variables. This means that their values can be reassigned after the initial assignment.

const
-----

The `const` keyword is for declaring constants. Once it’s assigned a value, it can have another value reassigned to it.

Flow can infer the data type constants without adding type annotation:

```javascript
const a = 1;
```

It’ll know that `a` is a number.

Of course, we can annotate it with a type as follows:

```javascript
const a: number = 1;
```

var and let
-----------

`var` and `let` are both for assigning to variables. The difference is that `var` isn’t block scoped while `let` is.

For example, we can write:

```javascript
if (true){  
  var x = 1;  
}  
console.log(x);
```

However, if we replace `var` with `let` , we’ll get an error:

```javascript
if (true){  
  let x = 1;  
}  
console.log(x);
```

We can reassign variables declared with `var` or `let` with another value. For example, we can write:

```javascript
var x = 1;  
x = 2;
let y = 1;  
y = 2;
```

Of course, if a data type annotation is added to a variable, then we must have a value with a compatible type assigned to it. For example, if we have a number variable:

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

Then writing:

```javascript
y = '2';
```

after it will create an error.

If a data type annotation isn’t added to a variable or constant, Flow will assume that the type of the variable or constant is the union of all the types of the data that had been assigned to it.

For example, if we have:

```javascript
let a = 1;  
a = 'foo';  
a = true
```

Then we can write:

```javascript
let b: number|string|boolean = a;
```

without getting any errors. This is because we assigned `a` a number, string and boolean before we assigned `a` to `b` , so `a` is assumed to have a union of all those types.

Flow can also figure out the type given that it’s been assigned. For example, we can write:

```javascript
let foo = 1;
let num: number = foo;
foo = false;
let boo: boolean = foo;
foo = "foo";
let str: string = foo;
```

However, code that’s run within blocks like functions and conditions will throw off Flow’s type inference and will throw an error when we try to assign it to something that we expect to work.

For example, if we write:

```javascript
let foo = 1;
if(true) {
  foo = true;
  foo = "foo";
}
let str: string = foo;
```

We’ll get the error:

```
[Flow] Cannot assign `foo` to `str` because number [1] is incompatible with string [2].
```

since Flow doesn’t know the type of the `foo` variable.

Likewise, Flow can’t figure out what type `foo` has after it’s been reassigned values inside a function as follows:

```javascript
let foo = 1;
const fn = ()=> {
  foo = true;
  foo = "foo";
}
fn();
let str: string = foo;
```

Function Types
==============

A function can have type annotations for its parameters and the return type of the function.

For example, if we have the function:

```javascript
function add(a: number, b: number): number {  
  return a + b;  
}
```

Then the `number` in `a: number` and `b: number` are the parameters’ data types, and the `number` after the close parentheses is the return type of the function `add` .

Once we annotate the parameters with types, Flow will validate the types when anything is passed in.

For example, if we have:

```javascript
add(1, 2);
```

Then Flow will accept the code as valid since we passed in numbers as indicated in the function definition.

On the other hand, if we pass in data of any other type like string as follows:

```javascript
add('a', 'b');
```

Then we get the error:

```
[Flow] Cannot call `add` with `'b'` bound to `b` because string [1] is incompatible with number [2].
```

Since we passed in strings for the arguments, which aren’t compatible with numbers.

Function Syntax
===============

Flow’s function syntax is similar to JavaScript but added extra type annotations to the parameters and return type.

We can have an infinite number of parameters with the rest operator, which is indicated with the `...` operator and holds the arguments that are excess of the listed parameters as an array.

For example, we can write:

```javascript
function foo(str: string, bool?: boolean, ...nums: Array<number>): void {
  console.log(nums);
}
foo('a', false, 1, 2, 3);
```

Then we get `[1,2,3]` for `nums` .

However, if we pass in something invalid as follows:

```javascript
foo('a', false, true, 2, 3);
```

Then we get an error for passing in `true` into the third argument since we specified that `...nums` is a number array.

We can declare variables and constants like JavaScript with Flow. In addition to JavaScript’s syntax, we can add data type annotations to variables and constants.

Function syntax and definition also extends from JavaScript’s syntax. Like variables, we can add data type annotations to variables, including ones operated on by the rest operator, and also add a return type annotation to a function.