Variable Types

Adding types to variable declarations

When you are declaring a new variable, you may optionally declare its type.

JavaScript has three ways of declaring local variables:

  • var - declares a variable, optionally assigning a value. (MDN)
  • let - declares a block scoped variable, optionally assigning a value. (MDN)
  • const - declares a block scoped variable, assigning a value that cannot be re-assigned. (MDN)

In Flow these fall into two groups:

  • let and var - variables that can be reassigned.
  • const - variables that cannot be reassigned.
1
2
3
4
5
6
7
8
var varVariable = 1;
let letVariable = 1;
const constVariable = 1;

varVariable = 2;   // Works!
letVariable = 2;   // Works!
// $ExpectError
constVariable = 2; // Error!

const

Since a const variable cannot be re-assigned at a later time it is fairly simple.

Flow can either infer the type from the value you are assigning to it or you can provide it with a type.

1
2
3
// @flow
const foo /* : number */ = 1;
const bar: number = 2;

var and let

Since var and let can be re-assigned, there’s a few more rules you’ll need to know about.

Similar to const, Flow can either infer the type from the value you are assigning to it or you can provide it with a type:

1
2
3
4
5
// @flow
var fooVar /* : number */ = 1;
let fooLet /* : number */ = 1;
var barVar: number = 2;
let barLet: number = 2;

When you provide a type, you will be able to re-assign the value, but it must always be of a compatible type.

1
2
3
4
5
// @flow
let foo: number = 1;
foo = 2;   // Works!
// $ExpectError
foo = "3"; // Error!
string This type is incompatible with number

When you do not provide a type, the inferred type will do one of two things if you re-assign it.

Reassigning variables

By default when you re-assign a variable, Flow will give it the type of all possible assignments.

1
2
3
4
5
6
let foo = 42;

if (Math.random()) foo = true;
if (Math.random()) foo = "hello";

let isOneOf: number | boolean | string = foo; // Works!

Sometimes Flow is able to figure out (with certainty) the type of a variable after re-assignment. In that case, Flow will give it the known type.

1
2
3
4
5
6
7
8
9
// @flow
let foo = 42;
let isNumber: number = foo; // Works!

foo = true;
let isBoolean: boolean = foo; // Works!

foo = "hello";
let isString: string = foo; // Works!

If statements, functions, and other conditionally run code can all prevent Flow from being able to figure out precisely what a type will be.

1
2
3
4
5
6
7
8
9
10
11
12
// @flow
let foo = 42;

function mutate() {
  foo = true;
  foo = "hello";
}

mutate();

// $ExpectError
let isString: string = foo; // Error!
boolean This type is incompatible with string number This type is incompatible with string

As Flow gets smarter and smarter there should be less of these scenarios.