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 typeof
types, which are types that are derived from other values.
The JavaScript Typeof Operator
In JavaScript, the typeof
operator is mostly useful for checking the type of primitive values. For example, it works for numbers, booleans, and strings:
typeof 2 === 'number'
typeof true === 'boolean'
typeof 'abc' === 'string'
For objects, it always returns 'object'
:
typeof { foo: 'abc' } === 'object'
Flow’s Typeof Operator
Flow’s typeof
operator is much more useful. It can be used to return the value of any type.
For example, it can get the type for numbers as follows:
let num = 42;
let num2: typeof num = 3.14;
It’ll fail when we assign values of any other type to it, like the following:
num2 = 'foo';
The benefit of Flow’s typeof
operator is that it can also be used for objects. For instance, if we have the following object:
let obj = { foo: 1, bar: true };
Then we can use the typeof
operator to assign the obj
object as a type of another object as follows:
let obj2: typeof obj = { foo: 1, bar: false };
As long as we have all the properties of obj
with the same data type, then it satisfies the requirement of the typeof obj
type.
We can do the same for arrays as follows:
let foo = [1, 2, 3];
let bar: typeof foo = [3, 2, 1];
typeof foo
will infer that the type of foo
is a number array, so we can assign another number array to bar
.
Type Inference
The typeof
operator does type inference implicitly. When we use literal values with Flow, then the inferred type is the primitive that the value belongs to.
For example, 1
would be a number
. We can override the inferred type by explicitly asserting the type of variable we define as follows:
let num1: 1 = 1;
Then assigning num1
to anything other than 1
will fail:
let num2: typeof num1 = 3;
The code above will give us an error.
Typeof’s Nominal Type Check
Like other parts of Flow, the typeof
operator also checks type nominally. This means that it checks the name rather than the structure. Therefore, even though 2 types have the same structure, but when their names are different, then they’re considered different.
For example, if we write:
class Foo {
foo(val: number) { }
}
class Bar {
foo(val: number) { }
}
Then the following assignment would work:
let x: typeof Foo = Foo;
because both types have the same name, but:
let y: typeof Foo = Bar;
would fail even though Foo
and Bar
have the same structure since the have different names.
With Flow’s typeof
operator, we can identify types of objects in addition to primitives. It’s consistent with Flow’s nominal type system in that it also checks the name by its name instead of the structure.
Also, the typeof
operator can infer types from the data that’s assigned to a variable. For example, if a variable is a number array, then using the typrof
operator on that array will return number array as the type.