Flow がオブジェクト指向プログラムから借用する最良の概念の1つは、ジェネリックスの概念です。 ジェネリックスが型チェックを洗練するために不可欠である多くの場合があります。

ジェネリックはどこで役に立ちますか?

関数memoizeがあるとしましょう。 フロータイプの場合、次のようになります。

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;
  };
}

問題は、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');

ジェネリックにする

パラメータの前にシェブロンで型を宣言し、それらを型として使用するのと同じくらい簡単です。

// 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;
  };
}

フローは残りを推測します:

// 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');