One of the best concepts Flow borrows from Object-Oriented programs is the concept of generics. There are many cases where generics are essential to refining type checks.

Where are Generics Useful?

generic illustration for: Where are Generics Useful?

Let's say you have a function memoize. With Flow types, it might look something like this:

				
					
function memoize(func: (key: any) => any): (key: any) => any {

  const registry = new Map();

  return function(key: any): any {

    let value = registry.get(key);

    if (typeof value === 'undefined') {

      value = func(key);

      registry.set(key, value);

    }

    return value;

  };

}

				
			

The problem is that it will swallow the specifics of func:

				
					
// Type is (val: number) => boolean

function isPrime(val: number): boolean {

  // Implementation...

}

// Type is (key: any) => any

const memoizedIsPrime = memoize(isPrime);

// This gives an error, since `Sentinel` is not a number.

isPrime('Sentinel');

// This does not give an error, since 'Sentinel' is any.

memoizedIsPrime('Sentinel');

				
			

Making it Generic

It's as simple as declaring types in chevrons before the parameters and using those as types:

				
					
// We're using `K` and `V` here for convention, but you can name them pretty much anything.

export default function memoize<K, V>(func: (key: K) => V): (key: K) => V {

  const registry = new Map();

  return function(key: K): V {

    let value = registry.get(key);

    if (typeof value === 'undefined') {

      value = func(key);

      registry.set(key, value);

    }

    return value;

  };

}

				
			

Flow will infer the rest:

				
					
// Type is (val: number) => boolean

function isPrime(val: number): boolean {

  // Implementation...

}

// Type is (key: K) => V.  Flow infers that `K` is number and `V` is boolean.

const memoizedIsPrime = memoize(isPrime);

// This gives an error, since `Sentinel` is not a number.

isPrime('Sentinel');

// This gives an error, since 'Sentinel' is a 'K' (number).

memoizedIsPrime('Sentinel');