flowの始め方

  • 8
    いいね
  • 0
    コメント

ということで、前回に引き続きReact Confで紹介されてたものを試すシリーズの第二回です。

flowの簡単な設定とeslint/babel/precommitフック/vimとの連携のみです。深い使い方は(今のところは?)書きません。flowは既に色々なところで紹介されてますが、気にせず行きます。

ちなみに今回もReactは出てきません。(追記で少しだけ触れてしまいました)

flowとは

  • JavaScript用のtypeチェッカー
  • ファイル単位で適用できるため、既存のプロジェクトにも気軽に導入できる
  • eslintやbabelとも連携できるので既存プロジェクトに導入しやすい
  • 色んなエディタ/IDEでもサポートされている
  • この辺を見る限りFacebookのデベロッパ的にはTypeScriptはあんまり推奨してないっぽい
  • GitHubのstarヒストリーを見る限りはTypeScriptに分がありそう
  • 数日程度弄った限りだと基本的なシンタックスは凄く簡単。でも複雑なことも色々できる模様。

使い方

前回eslintとprettierを導入した環境に追加していきます。
ソースはここにあります。便宜上ディレクトリは分けました。

単体で使う

まずはflowをインストールして初期化します。

yarn add -D flow-bin 
flow init

空の.flowconfigができるので、以下のようにnode_modulesをチェック対象外にします。

[ignore]
.*/node_modules/.*

[include]

[libs]

[options]

テスト用にエラーになるjsファイルを作ってみます。

index.js
/* @flow */

var a: number = 1;

a = 'string';

先頭のコメントはflowのチェック対象にするために必要です。

この状態でflow checkコマンドを実行するとnumberで宣言した変数にstringを入れようとしているので、エラーになります。

$ flow check
index.js:5
  5: a = 'string';
         ^^^^^^^^ string. This type is incompatible with
  3: var a: number = 1;
            ^^^^^^ number


Found 1 error

babelと連携する

babelと連携するにはbabel-plugin-transform-flow-strip-typesが必要です。

babel自体とes2015のpresetと一緒に導入してみます。

yarn add -D babel-cli babel-preset-es2015 babel-plugin-transform-flow-strip-types

そして以下のような内容で.babelrcを作ります。

.babelrc
{
  "plugins": ["transform-flow-strip-types"],
  "presets": ["es2015"]
}

そしてjsをletを使うように変更してbabelを実行してみます。

index.js
/* @flow */

let a: number = 1;

a = "string";
babel index.js --out-dir dist

出力されたindex.jsを見ると適切に変換されているのがわかります。

dist/index.js
"use strict";

var a = 1;

a = "string";

eslintと連携する

このままだと: numberなどのTypeアノテーションがeslintのチェックを通りません。

eslintと連携するにはbabel-eslinteslint-plugin-flowtypeをインストールする必要があります。

yarn add -D eslint-plugin-flowtype babel-eslint

.eslintrc.jsに以下を追加します。中身は明らかなので説明は要らないかと思います。

eslintrc.js
  parser: 'babel-eslint',
  extends: ['plugin:flowtype/recommended'],
  plugins: ['flowtype'],
  settings: {
    flowtype: {
      onlyFilesWithFlowAnnotation: true,
    },
  },

precommitフック

前回作ったprecommitフックにflowを追加して、flowのtypeチェックが失敗したらコミットをabortするようにします。

package.json
  "scripts": {
    "precommit": "lint-staged && flow check"
  },

この状態でflowでエラーになるファイルをコミットしようとすると、エラーを吐いて止めてくれます。

$ git add index.js
$ git commit -m 'flow test'

> husky - npm run -s precommit

 ↓ Running tasks for gitDir [skipped]
   → No staged files match gitDir
 ✔ Running tasks for *.js
index.js:5
  5: a = "string";
         ^^^^^^ string. This type is incompatible with
  3: let a: number = 1;
            ^^^^^^ number


Found 1 error

> husky - pre-commit hook failed (add --no-verify to bypass)
> husky - to debug, use 'npm run precommit'

js以外のリソースに対応する

js以外のリソース(フロントだとcss、バックエンドだとsql等)があるとRequired module not foundというエラーが出てしまいます。
こんなときは以下のようなファイルを作って、

flow/SQLAsset.js.flow
/* @flow */
declare export default string

.flowconfigoptionsに以下を追記すると解消できます。

[options]
module.name_mapper.extension='sql' -> '<PROJECT_ROOT>/flow/SQLAsset.js.flow'

エディタ連携

色々なエディタがサポートされてるようですが、とりあえずvim連携を試します。これは公式アカウントが提供しているvim-flowを入れればOKです。

以下はdeinの例

dein.toml
[[plugins]]
repo = 'flowtype/vim-flow'
on_ft = ['javascript', 'javascript.jsx']

flowのパスは適宜init.vimや.vimrc等で設定してください。

let g:flow#flowpath = l:bin_folder . 'flow'
let g:flow#autoclose = 1 " エラーを表示するquickfixのウィンドウをエラーがなくなり次第閉じる

これで保存時に自動でflowのチェックが走り、エラーがあるとquickfixウィンドウにエラーを表示してくれます。

シンタックスハイライトはvim-javascriptが対応しているので、以下を追加するだけでOKです。

let g:javascript_plugin_flow = 1

追記

flow-typed(2017/03/25)

.flowconfigでnode_modules全体をignoreに指定して外すとnode_modules内のモジュールをimportしたときにエラーになります。
これを解決するにはflow-typedを使います。
一部のライブラリは既にflow-typedを通じて型情報を提供しているので、yarn add -D flow-typedしてからflow-typed installするとpackage.jsonで指定したライブラリのうちflow-typedに対応している型情報をflow-typedディレクトリに入れてくれます。また対応していないものもany型でのstubが作成されるためflowがエラーを吐かなくなります。なお、これはデフォルトで解決できるようになるので、.flowconfigの[libs]セクションにflow-typedディレクトリを明示的に指定する必要はありません。

yarn add -D flow-typed
flow-typed install

PropTypesをflowに変換する(2017/5/1)

Reactv15.5.0からPropTypesが別パッケージになりました
PropTypes使うよりもflowでチェックした方が実行前に型チェックができるのでより安全です。codemod-proptypes-to-flowを使うとPropTypesをflowに自動的に変換してくれます。いくつかの制約はありますが、今後はある程度の制約を受け入れてflowに移行したほうが良いのではないかと思います。インストールして実行するだけなので手順は省略します。

カバレッジを取得(2017/5/1)

flow-coverage-reportを使うとflowのtypeのカバレッジを取得することができます。これまたインストールして実行するだけなので手順は省略します。

最後に

以上、参考になれば幸いです。
ちなみにprettierはデフォルトでflowに対応しているので、特に設定不要です。