Categories
Flow JavaScript

JavaScript Type Checking with Flow — More Utility Types

Spread the love

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.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *