flowの型情報をnpmパッケージで一緒に配布する

  • 7
    いいね
  • 1
    コメント

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.jsfoo.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 ファイルが生成される。

package.json(抜粋)
{
  "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 について説明がある。

  1. babel は babel-preset-flow を使うように設定されている。