シンクロ・フード エンジニアブログ

飲食店.COMを運営する、株式会社シンクロ・フードの技術ブログです

Flow で静的型付けしながらフロントエンド開発した話

基盤チームの川井 (@fohte) です。

今回は飲食店リサーチというサービスのフロントエンドを Flow で型付けしながら React で開発して得た知見の話をします。

Flow とは?

Flow は Facebook 社が開発した、JavaScript の構文を拡張して静的型解析機能を提供するツールです。
例えば以下のような Flow を使ったコードは、Flow の型チェックによって事前にバグを検出することができます。

/* @flow */
function square(n: number): number {
  return n * n
}

square('2') // エラー

嬉しいですね。雑にコードを書いていても Flow が型の不一致を警告してくれるため、書いたコードに対して安心感が生まれます。さらに型解析により定義元ジャンプや補完も効くため、開発効率は大きく向上することでしょう。

Flow はあくまで静的型解析機能のみを提供するため、TypeScript などとは異なりそれ自身でトランスパイルは行なえません。実用するためには拡張された構文だけを取り除く以下のようなツールを用いて通常の JavaScript に変換する必要があります。

トランスパイルがほぼ必須となることから気軽さは少ないですが、既に JavaScript のビルド環境が整っている場合には導入しやすいです。

なぜ Flow を使うのか

今回開発した飲食店リサーチというサービスではフォームが動的に生成され、また入力内容によってフォームが動的に変化するという要件がありました。これを実現するためにはそれなりのコード量を必要とする複雑な処理を書く必要があり、そこで静的型解析ができればコード量が増えても安心できるプログラムが書きやすいのではと考え、Flow の導入に踏み切りました。

なぜ TypeScript ではないのか

同じく静的型付き言語の AltJS である TypeScript は、たびたび Flow と比較して語られます。静的型解析が欲しいという要求には TypeScript は十分に満たしているため TypeScript でも問題はありませんでしたが、既に webpack + Babel でのビルド環境が整っていたため、それに乗っかる形で今回は Flow を選択しました。

TypeScript と Flow で機能面での差はほとんどありませんが、TypeScript を選択するメリットとして、コミュニティが Flow よりも大きく (Flow も大きいですが) 歴史も長いためドキュメントが豊富です。 Flow は公式のドキュメントにない情報も少なくなく、また問題が発生したときもリポジトリの issues を見に行くしかないことが多い印象があります。

Flow は着実にバージョンアップを重ねており、このような問題も次第に解消されることを期待しています。

Flow を導入した所感

今回の開発は長期的にかつ断続的に続いたため過去のコードを思い出す手間がありましたが、型定義がドキュメント代わりになっていてその手間はほとんど省けました。静的に型チェックができることで、自分がコードを忘れていても型が間違っていれば即座にエラーになりますし、非常に体験が良かったです。

一方でデメリットとして、複雑な型を表現すると Flow 特有の知識が必要になり、ドキュメントが少ないことも相まって学習難度が上がってしまいます。難しい代表例としては、ある型から別の型を生成する Utility Types が挙げられます。例えばある object 型の key を全て read-only にしたいとき、$ReadOnly を用いればそれを表現できます。

type Props = {
  x: string,
  y: number,
  z: boolean,
}

type ReadOnlyProps = $ReadOnly<Props>

function render(props: ReadOnlyProps) {
  console.log(props.x) // OK
  props.x = 'foobar' // Error

  // ...
}

このような Utility Types は柔軟に型を表現できますが、Flow に慣れていないと難読な型表現になってしまいます。 Utility Types を駆使しないと表現できない型もあり、全てを厳密に型付けしようとすると消耗してしまいます。ときには型検査を捨てる any type を使い、型定義を妥協することが必要になることもあります。 *1

まとめ

今回は JavaScript に静的型解析機能を提供する Flow を紹介しました。型定義に苦戦することはあるものの、静的型解析で受けられる恩恵は非常に大きいです。

ぜひ快適な静的型解析生活を!


シンクロ・フードではフロントエンド開発に興味のあるエンジニアも募集しています。ご興味のある方は以下よりご連絡ください!

*1:mixed type という逃げもあります。