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.