The possible data types definitions can be found at https://flow.org/en/docs/types/—we won't copy them all here, but rather show you the main ones through a few examples. Please look at the full documentation because there's a great variety of possibilities that you should be aware of:
:boolean
|
Boolean values. |
:number
|
Numeric values. |
:string
|
Strings. |
:null
|
Null values. You wouldn't just be declaring that a certain variable should always be null; rather, you'll be using these with advanced types such as unions, which we'll get to see in the next section. |
:void
|
Void (undefined) value. |
:mixed
|
Any type, but will still get checked for consistency. For instance, if at one point Flow knows that the variable is a Boolean, then using it as a string would be flagged as wrong. |
:any
|
Any type, and Flow won't do any checks for it. This amounts to disabling type checks on whatever is of any type. |
function foo(x: ?boolean)
|
A function with an optional boolean parameter. This is the same as declaring that the argument can either be a boolean, null, or also undefined. |
function bar() :string
|
A function that returns a string result. |
{ property ?: number }
|
An optional object property; if present, it could be numeric or undefined, but not null. |
: Array<number>
: number[] |
An array of numbers, in two different styles. If you want to deal with fixed length arrays, tuples may apply; go to https://flow.org/en/docs/types/tuples/ to find out more. |
We can see some examples of the definitions in the following code. I disabled ESLint's rule about unused variables to avoid obvious problems:
// Source file: src/types_basic.js
/* @flow */
/* eslint-disable no-unused-vars */
let someFlag: boolean;
let greatTotal: number;
let firstName: string;
function toString(x: number): string {
return String(x);
}
function addTwo(x: number | string, y: number | string) {
return x + y;
}
function showValue(z: mixed): void {
// not returning anything
console.log("Showing... ", z);
}
let numbersList: Array<number>;
numbersList = [22, 9, 60]; // OK
numbersList[1] = "SEP"; // error; cannot assign a string to a number
let anotherList: number[] = [12, 4, 56];
// continues...
When you define an object, you should provide data types for all of its properties and methods. Object definitions are considered to be sealed, meaning that you cannot change the object types. If you cannot or won't do this, start with an empty object, and then Flow will let you add properties at will:
// ...continued
let sealedObject: { name: string, age?: number } = { name: "" };
sealedObject.name = "Ivan Horvat"; // OK
sealedObject.id = 229; // error: key isn't defined in the data type
sealedObject = { age: 57 }; // error: mandatory "name" field is missing
let unsealedObject = {};
unsealedObject.id = 229; // OK
Now, let's turn to more complex definitions, which you will probably end up using, since they better match usual business requirements and program specifications.