Primitive Types
JavaScript has a number of different primitive types (MDN):
| Example | Flow type | |
|---|---|---|
| Booleans |
true or false
|
boolean |
| Strings | 'foo' |
string |
| Numbers | 123 |
number |
| Null | null |
null |
| Undefined | undefined |
void |
| Symbols (new in ES2015) | Symbol('foo') |
symbol |
| BigInts (new in ES2020) | 123n |
bigint |
Some primitive types appear in the language as literal values:
true; "hello"; 3.14; null; undefined; 3n;
BigInts and Symbols can be created with calls to BigInt and Symbol, respectively:
BigInt("2364023476023");
Symbol("hello"); The Flow types of literal values are lowercase (mirroring the output of JavaScript's typeof expression):
function func(a: number, b: string, c: boolean, d: bigint) { /* ... */ }
func(3.14, "hello", true, 3n); Some literals can also be used as literal types:
function acceptTwo(x: 2) { /* ... */ }
acceptTwo(2); // Works!
acceptTwo(1); // Error! Some primitives can also be wrapped as objects:
NOTE: You probably never want to use the wrapper object variants.
new Boolean(false);
new String("world");
new Number(42); Types for the wrapper objects are capitalized (the same as their constructor):
function func(x: Number, y: String, z: Boolean) {
// ...
}
func(new Number(42), new String("world"), new Boolean(false)); These wrapper objects are rarely used.
Booleans
Booleans are true and false values in JavaScript. The boolean type in Flow accepts these values.
function acceptsBoolean(value: boolean) { /* ... */ }
acceptsBoolean(true); // Works!
acceptsBoolean(false); // Works!
acceptsBoolean("foo"); // Error! JavaScript can also implicitly convert other types of values into booleans.
if (42) {} // 42 => true
if ("") {} // "" => false Flow understands these coercions and will allow them as part of an if statement's test or other conditional contexts.
To explicitly convert non-booleans to a boolean, you can use Boolean(x) or !!x.
function acceptsBoolean(value: boolean) { /* ... */ }
acceptsBoolean(0); // Error!
acceptsBoolean(Boolean(0)); // Works!
acceptsBoolean(!!0); // Works! You can refine a value to boolean using a typeof check:
function acceptsBoolean(value: boolean) { /* ... */ }
function func(value: unknown) {
if (typeof value === 'boolean') {
acceptsBoolean(value); // Works: `value` is `boolean`
}
} Remember that boolean and Boolean are different types.
- A
booleanis a literal value liketrueorfalseor the result of an expression likea === b. - A
Booleanis a wrapper object created by the globalnew Boolean(x)constructor. You probably don't want to use this!
Numbers
Number literals in JavaScript are floating point numbers, for example 42 or 3.14. JavaScript also considers Infinity and NaN to be numbers. These are represented by the number type. JavaScript also has a separate BigInt type.
function acceptsNumber(value: number) { /* ... */ }
acceptsNumber(42); // Works!
acceptsNumber(3.14); // Works!
acceptsNumber(NaN); // Works!
acceptsNumber(Infinity); // Works!
acceptsNumber("foo"); // Error!
acceptsNumber(123n); // Error! You can refine a value to number using a typeof check:
function acceptsNumber(value: number) { /* ... */ }
function func(value: unknown) {
if (typeof value === 'number') {
acceptsNumber(value); // Works: `value` is `number`
}
} Remember that number and Number are different types.
- A
numberis a literal value like42or3.14or the result of an expression likeparseFloat(x). - A
Numberis a wrapper object created by the globalnew Number(x)constructor. You probably don't want to use this!
Strings
Strings are "foo" values in JavaScript. The string type in Flow accepts these values.
function acceptsString(value: string) { /* ... */ }
acceptsString("foo"); // Works!
acceptsString(`template literal`); // Works!
acceptsString(false); // Error! JavaScript implicitly converts other types of values into strings by concatenating them.
"foo" + 42; // "foo42"
"foo" + {}; // "foo[object Object]" Flow will only accept strings and numbers when concatenating them to strings.
"foo" + "foo"; // Works!
"foo" + 42; // Works!
`foo ${42}`; // Works!
"foo" + {}; // Error!
"foo" + []; // Error!
`foo ${[]}`; // Error! You must be explicit and convert other types into strings. You can do this by using the String function or using another method for stringifying values.
"foo" + String({}); // Works!
"foo" + [].toString(); // Works!
"" + JSON.stringify({}) // Works! You can refine a value to string using a typeof check:
function acceptsString(value: string) { /* ... */ }
function func(value: unknown) {
if (typeof value === 'string') {
acceptsString(value); // Works: `value` is `string`
}
} Remember that string and String are different types.
- A
stringis a literal value like"foo"or the result of an expression like"" + 42. - A
Stringis a wrapper object created by the globalnew String(x)constructor. You probably don't want to use this!
null and undefined
JavaScript has both null and undefined. Flow treats these as separate types: null and void (for undefined).
function acceptsNull(value: null) { /* ... */ }
acceptsNull(null); // Works!
acceptsNull(undefined); // Error!
function acceptsUndefined(value: void) { /* ... */ }
acceptsUndefined(undefined); // Works!
acceptsUndefined(null); // Error! Flow has no undefined type — only void. TypeScript's T | undefined corresponds to Flow's T | void. See void vs undefined for the full comparison.
You can refine a value to null or void using equality checks:
function acceptsNull(value: null) { /* ... */ }
function func(value: unknown) {
if (value === null) {
acceptsNull(value); // Works: `value` is `null`
}
} function acceptsUndefined(value: void) { /* ... */ }
function func(value: unknown) {
if (value === undefined) {
acceptsUndefined(value); // Works: `value` is `void`
}
} null and void also appear in other types:
Maybe types
Maybe types are for places where a value is optional and you can create them by adding a question mark in front of the type such as ?string or ?number.
?T is equivalent to T | null | void.
function acceptsMaybeString(value: ?string) { /* ... */ }
acceptsMaybeString("bar"); // Works!
acceptsMaybeString(undefined); // Works!
acceptsMaybeString(null); // Works!
acceptsMaybeString(); // Works! To refine, value == null checks exactly for both null and undefined.
Read the maybe type docs for more details.
Optional object properties
Object types can have optional properties where a question mark ? comes after the property name.
{propertyName?: string} In addition to their set value type, these optional properties can either be void or omitted altogether. However, they cannot be null.
function acceptsObject(value: {foo?: string}) { /* ... */ }
acceptsObject({foo: "bar"}); // Works!
acceptsObject({foo: undefined}); // Works!
acceptsObject({}); // Works!
acceptsObject({foo: null}); // Error! Optional function parameters
Functions can have optional parameters where a question mark ? comes after the parameter name.
function func(param?: string) { /* ... */ } In addition to their set type, these optional parameters can either be void or omitted altogether. However, they cannot be null.
function acceptsOptionalString(value?: string) { /* ... */ }
acceptsOptionalString("bar"); // Works!
acceptsOptionalString(undefined); // Works!
acceptsOptionalString(); // Works!
acceptsOptionalString(null); // Error! Function parameters with defaults
Function parameters can also have defaults. This is a feature of ES2015.
function func(value: string = "default") { /* ... */ } In addition to their set type, default parameters can also be void or omitted altogether. However, they cannot be null.
function acceptsOptionalString(value: string = "foo") { /* ... */ }
acceptsOptionalString("bar"); // Works!
acceptsOptionalString(undefined); // Works!
acceptsOptionalString(); // Works!
acceptsOptionalString(null); // Error! Symbols
Symbols are created with Symbol() in JavaScript. Flow has basic support for symbols, using the symbol type.
function acceptsSymbol(value: symbol) { /* ... */ }
acceptsSymbol(Symbol()); // Works!
acceptsSymbol(Symbol.isConcatSpreadable); // Works!
acceptsSymbol(false); // Error! You can refine a value to symbol using a typeof check:
function acceptsSymbol(value: symbol) { /* ... */ }
function func(value: unknown) {
if (typeof value === 'symbol') {
acceptsSymbol(value); // Works: `value` is `symbol`
}
} BigInts
BigInts can be used to represent integers of arbitrary precision. In other words, they can store integers which are too large to store as a number.
A bigint literal is just a number literal along with an n suffix.
Note that bigint and number are incompatible types. That is, a bigint cannot be used where a number is expected, and vice versa.
function acceptsBigInt(value: bigint) { /* ... */ }
acceptsBigInt(42n); // Works!
acceptsBigInt(42); // Error! You can refine a value to bigint using a typeof check:
function acceptsBigInt(value: bigint) { /* ... */ }
function func(value: unknown) {
if (typeof value === 'bigint') {
acceptsBigInt(value); // Works: `value` is `bigint`
}
} See Also
-
Literal Types — using specific primitive values (like
2or"foo") as types -
Maybe Types — making any type nullable with the
?Tshorthand -
Refinements — narrowing from broad types to specific primitives using
typeof
© 2013–present Facebook Inc.
Licensed under the MIT License.
https://flow.org/en/docs/types/primitives