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 the built-in more utility types that come with Flow.
$NonMaybeType<T>
$NonMaybeType<T>
converts type T
to a non-maybe type. This means that we can’t assign null
or undefined
to any properties of the type that’s return returned with this utility type.
We can use it as follows:
type MaybeAge = ?number;
type Age = $NonMaybeType<MaybeAge>;
let age: Age = 1;
We can’t assign null
or undefined
to anything fo type Age
:
let age2: Age = null;
The code above will give an error.
$ObjMap<T, F>
$ObjMap<T, F>
returns a type that’s maps the object type T
by the function type F
.
For example, if we have a type for a mapping function:
type ExtractReturnType = <V>(() => V) => V;
Then we have the following function that runs a function:
function run<O: Object>(o: O): $ObjMapi<O, ExtractReturnType>{
return Object.keys(o).map(key => o[key]());
}
Then given that we have the following object:
const o = {
a: () => 1,
b: () => 'foo'
};
Then we can get the return type of the method of the o
object as follows:
(run(o).a: number);
(run(o).b: string);
$ObjMapi<T, F>
$ObjMapi<T, F>
is similar to $ObjMap<T, F>
but F
will be called with both the key and value types of the elements of the object type T
.
For example, if we have:
type ExtractReturnType = <V>(() => V) => V;
function run<O: Object>(o: O): $ObjMapi<O, ExtractReturnType>{
return Object.keys(o).map(key => o[key]());
}
const o = {
a: () => 1,
b: () => 'foo'
};
Then we get the following types returned for a
and b
:
(run(o).a: { k: 'a', v: number });
(run(o).b: { k: 'b', v: string });
In the code above, k
is the key of o
and v
is the corresponding value of keys from o
.
$TupleMap<T, F>
$TupleMap<T, F>
takes an iteral type like tuples or arrays T
and a function type F
and returns the iterable type obtained by mapping each value in the iterable with each entry being a function of type F
.
It’s the same as calling map
in arrays in JavaScript.
For example, we can use it as follows:
type ExtractReturnType = <V>(() => V) => Vfunction run<A, I: Array<() => A>>(iter: I): $TupleMap<I, ExtractReturnType> {
return iter.map(fn => fn());
}
const arr = [() => 1, () => 2];
(run(arr)[0]: number);
(run(arr)[1]: number);
Note that the return type of each function in the arr
array have to be the same. Otherwise, we’ll get an error.
$Call<F, T...>
$Call<F, T…>
is a type that results in calling the function with type F
with 0 or more arguments T...
. It’s analogous to calling a function at run time but the type is returned instead.
For example, we can use it as follows:
type Add = (number, number) => string;
type Sum = $Call<Add, number, number>;
let x: Sum = '1';
In the code above, given that we have the Add
type, which is function type that takes in 2 numbers and returns a string. We created a new type from it by writing:
type Sum = $Call<Add, number, number>;
Then we get that the Sum
type is a string.
We can also write:
const add = (a: number, b: number) => (a + b).toString();
type Add = (number, number) => string;
type Sum = $Call<typeof add, number, number>;
let x: Sum = '1';
As we can see, it’s useful for getting the return type of a function without actually calling it.
Class<T>
Class<T>
is used for passing in the type into a class. It lets us make a generic class that can take on multiple types.
For example, given the following class:
class Foo<T>{
foo: T;
constructor(foo: T){
this.foo = foo;
} getFoo(): T {
return this.foo;
}
}
We can use it to create multiple classes:
type NumFoo = Foo<number>;
type StringFoo = Foo<string>;
Then we can instantiate the classes as follows:
let numFoo: NumFoo = new Foo<number>(1);
let stringFoo: StringFoo = new Foo<string>('abc');
$Shape<T>
$Shape<T>
is a type that contains a subset of the properties included in T
.
For example, given the Person
class:
type Person = {
name: string,
age: number
}
Then we can use the $Shape<T>
type as follows:
const age: $Shape<Person> = { age: 10 };
Notice that we didn’t include the name
property in the object assigned.
$Shape<T>
isn’t the same as T
with all its fields marked optional. $Shape<T>
can be cast into T
. For example, the age
constant that we defined earlier can be cast as follows:
(age: Person);
$Exports<T>
$Exports<T>
lets us import types from another file. For example, the following are the same:
import typeof * as T from './math';
type T = $Exports<'./math'>;
In Flow, we have specific utility types for objects which have methods to the return type of methods. Also, we have a type for mapping iterable objects with functions of the same return type to the return type of each function.
In addition, there’s the Class<T>
utility type for defining generic classes, the $Shape<T>
type for getting a subset of properties of type T
as its own type.
There’s also the $Call<F, T,...>
for retrieving the return type of F
without calling it.
Finally, we have the $Exports<T>
type for getting the types from another file.