こないだReactで書きなおしたウデマエアーカイブに、Flowをいれてみようと思って、しばらく色々と試したことのメモ、もとい奮闘記です。
事前準備
npm i --save-dev babel-plugin-transform-flow-strip-types npm i -g flow-bin
まず最初に、`babel-plugin-transform-flow-strip-types`をいれる。
型についての記載を実コードから削ってくれるやつ。
次に、グローバルに`flow-bin`をインストールしておく。
最後にエディタをいい感じに。
開発はVimでやるので、SyntasticとFlowを連携させる。
let g:syntastic_javascript_checkers = ['eslint', 'flow']
ってな具合に指定するだけ。
というわけで現在Flowを使うには、Babelを使う前提があるというわけではある
事前準備の補足
公式とか検索して出てくるものは、`transform-flow-strip-types`さえいれればOK!ってなってるけど、ちょっと罠があります。
それは、使ってるモジュールの仕組みがES Modulesか、CommonJSかで違います。
あと、`transform-class-properties`を使ってるかどうかも関係するので、以下の表で当てはまるやつを準備する。
Module | transform-class-properties | どうすればいいか |
---|---|---|
CommonJS | してる | `transform-flow-strip-types`足す |
CommonJS | してない | `transform-class-properties`も足す OR `passPerPreset`で先に`transform-flow-strip-types`する |
ES Modules | してる | `transform-flow-strip-types`足す |
ES Modules | してない | `transform-class-properties`するしかない(`passPerPreset`で先に`transform-flow-strip-types`してもNG) |
ちなみにコレ、Classに型をつけるまでは問題になりません、ってのが罠やと思うの・・。
`passPerPreset`
Babel 6.5から入ったExperimentalな機能。
{ passPerPreset: true, presets: [ { "plugins": [ "babel-plugin-transform-flow-strip-types" ] }, "es2015", "react" ] }
`.babelrc`にこう書けばいい。
.flowconfig
準備ができたらいざ型付け!
ということで、Flowの設定ファイル`.flowconfig`を用意する。
flow init
Flowをグローバルにインストールしたらこのコマンドが使えるので、これで生成してもいい。
ちな現在の`.flowconfig`はこんな感じ。
[ignore] .*/node_modules/.* .*/dist/.* [include] [libs] ./src/script/_decls [options] suppress_comment= \\(.\\|\n\\)*\\flow-disable-line
ハマりどころ1
これを生成した時点では、`.flowconfig`が置かれたルートから全ファイルをチェックしにいってしまう。
もちろん`node_modules`配下も例外ではないわけで、だいたい型が指定されてないよエラーで爆散するはず。
というわけで`ignore`する。
buildしたファイルも見なくていいので`ignore`する。
ここのパスの書き方がOCamlの正規表現らしく、ちょっと慣れない感じ。
flow ls
これでいまFlowがターゲットとしてるファイルのリストが出るので、確認しながら調整すればOK。
ハマりどころ2
`node_modules`を無視したので、読み込んだライブラリにも自分で型をつける必要が出てくる。
その定義を置いておくのが`libs`で指定したディレクトリ。
この指定したディレクトリ配下においた`**.js`を、型定義として読み込んでくれる。
1つのファイルに全部書くぜ!って場合は、「ファイル名をフルパス」で指定すればOK。
[libs] ./src/script/_decls # ディレクトリ指定なら ./src/script/_decls.js # ファイル指定なら
ハマりどころ3
せっかく型を付けられるようになったし、できれば全ファイルで`@flow`って書きたいところ。
でも中にはどうしようもないやつもいて・・、たとえばGoogleAnalyticsのコード。
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments);},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m); })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
これがすごい怒られる。
1行ずつ分解してあるべきところに型をつけて・・ってやっていくと通るけど、なんでそんなことをせなあかんのかという気持ちが強い。
そこで、ESLintにある「この行はLintしなくていいよコメント」みたいなのないかなー?と思ってたらあった。
`.flowconfig`の`options`に、`suppress_comment`ってのを指定する。
[options] suppress_comment= \\(.\\|\n\\)*\\flow-disable-line
こう書いたうえで、
// flow-disable-line (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments);},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m); })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
これで無視できるようになった。
いざ型付け!
ファイルの先頭に`@flow`コメントを入れると、Flowがチェックしてくれるようになる。
むしろ、このコメントがないとチェックしてくれない。
行コメントでもいいし、複数行コメントでもいいけど、他のどんなコード記述よりも前である必要がある。
/** * このファイルは.... * なんたらかんたら... * * @flow */
これでもOK。
というわけで、
- 1ファイルずつ、`@flow`コメントいれる
- Flowに怒られる部分があるので、そこをなおす
- より厳密にしたい部分に型を付けていく
という手順でやっていきます。
やってみての学びは、また次のPart.2に書きます!