TL;DR;
- flow 0.19.0 から .js.flow 拡張子がついたファイルがあればそれを見るようになった
- npm パッケージでは型情報を消した .js ファイルと、型情報を持った .js.flow ファイルを一緒に配布する
- 将来的に flow に特大の後方非互換な変更が入らない限り動くはず
npmパッケージも型情報を使いたい
開発時に型情報を書いても、いざ配布するときにはそれを取り外してから配布する。取り外さないと、 flow を使っていないプロジェクトで require
することが困難になってしまうためだ。
しかし、そのパッケージを使うときには flow を使いたい。flowtype/flow-typed に自分のライブラリの情報を載せるのが一つの手だが、開発段階で実装が流動的だと更新が面倒なのに加えて、そもそも DRY ではない。
せっかく開発時に書いた型情報を、 npm パッケージとして require したときに使うことはできないのだろうか。
Declaration files
なぜか flow.org の標準ドキュメントで言及されていないのだが、 0.19.0 で追加された declaration files という機能を使うと簡単に実現できる。
Declaration files とは、簡単な話が foo.js
と foo.js.flow
というファイルがあり、 import Foo from './foo'
を実行したら flow は foo.js.flow
を見に行く、というものだ。
つまり型情報を取り除いた .js ファイルとは別に、型情報が残ったままのファイルを .js.flow という名前でパッケージに入れればいい。
npm パッケージに書き込まれているということは、パッケージを使っているプロジェクトで利用している flow のバージョンによってはエラーが発生する可能性があるということだ。特に将来的に flow 本体に後方非互換な変更が入った場合、それによってパッケージを使っている側の型チェックが通らなくなってしまう。この場合は .flowconfig でそのパッケージを ignore するように設定してしのぐことになると思われる。
例: yuku-t/textcomplete
textcomplete は src ディレクトリの下に @flow
プラグマが指定された .js ファイルが入っている。これを npm run build:lib
でビルドすると lib ディレクトリの下に babel でトランスパイルされた .js ファイルと1、 src ディレクトリにもともとあったそのままの .js.flow ファイルが生成される。
{
"script": {
"build:lib": "babel src -d lib -s && for js in src/*.js; do cp $js lib/${js##*/}.flow; done"
}
}
この結果 textcomplete を require
すると flow は型情報にアクセスすることができるようになっている。
参考
- Version 0.19.0 - 0.19.0 のリリースブログ。 Declaration files について説明がある。
-
babel は babel-preset-flow を使うように設定されている。 ↩