Reactのコンポーネントにpropsを渡さない場合のFlowの書き方

Flowのバージョンは0.61.0で確認している。

propsを渡さない場合、Flowはどのように指定すればよいのか

ReactのコンポーネントのpropsにFlowで型をつける場合、以下のように書く。

type Props = {
  foo: string,
};

class ChildComponent extends React.Component<Props> {
  render() {
    return <div>{this.props.foo}</div>;
  }
}
class ParentComponent extends React.Component {
  render() {
    return <ChildComponent foo="hoge" />;
  }
}

https://flow.org/en/docs/react/components/

では、このコンポーネントにはpropsを渡さない場合は、どう書けばいいのか。

propsは、何も渡されなかった場合、空のオブジェクトになる。

class ChildComponent extends React.Component<Props> {
  render() {
    console.log(this.props); // {}
    return <div>foo</div>;
  }
}
class ParentComponent extends React.Component {
  render() {
    return <ChildComponent />;
  }
}

なので、空のオブジェクトを型として設定してみる。

type Props = {};

しかしこれだと、propsを渡してもエラーがでない。
間違ってpropsを渡してしまった場合はエラーを出してくれないと、型として機能していない。

結論を書くと、以下のように定義すればよい。

type Props = {||};

これは、Exact object typesという表記を使って「空のオブジェクト」を定義したものである。

Exact object types

Flowでは通常、指定していないプロパティがオブジェクトに含まれていても、エラーにはならない。
例えば下記の例では、引数として渡したオブジェクトに指定していないプロパティ(boo)が含まれているが、エラーにはならない。

// @flow

function method(obj: {foo: string}) {
  return obj;
}

method({
  foo: '1', // Works!
  boo: 2, // Works!
});

先程のpropsのケースも、これが原因だった。
空のオブジェクトを指定した場合、それはむしろ、あらゆるプロパティを許容することになってしまう。

// @flow

function method(obj: {}) {
  return obj;
}

method({
  foo: '1', // Works!
  boo: 2, // Works!
});

これを防ぎ、厳密にオブジェクトを定義したいときに使うのが、Exact object typesである。
{||}で囲めばよい。

// @flow

function method(obj: {|foo: string|}) {
  return obj;
}

method({
  foo: '1', // Works!
  boo: 2, // Error!
});

そのため、空のオブジェクトは中に何も書かず{||}と定義すればよい。
この場合、空のオブジェクト以外が渡された場合はエラーを出してくれる。

参考資料