概要
javascriptの静的型付けのチェックを行うツールであるflowというツールを導入し、業務で開発しているプロダクトの品質向上を目指そうと考えています。
既にpure javascriptで書かれた環境があるので、このコードを書き直さずにflowを導入したいと考えており、導入方法について調べた内容をまとめます。
github.com
flowを使った従来の型チェック
一般的に、flowを使ってjavascriptコードの型チェックを行うためには、flow独自のsyntaxでコードを記述し、 実環境へのデプロイは、babelを使ってpure javascriptのコードへトランスパイルするのが一般的です。
// flow独自のsyntaxで記述 // @flow function square(n: number): number { return n * n; } square("2"); // Error!
既に本番運用されているプロダクトへのflowの導入の辛さ
しかし、既にpure javascriptで記述して運用されている実環境において、flowを導入するために、イチからflow syntaxで書き直すのは現実的ではありません。
デプロイ処理にbabelを使った pure javascriptへのトランスパイルを挟む必要があるし、テスト周りの処理も見直さなければなりません。
そもそもトランスパイルを挟むなら、型指定のあるtypescriptにまるっとコードを置き換えたほうが良いかと思います。
型チェックのために、コードをflow用に書き直すことなく、pure javascriptでflowの型チェックの利点を活かす事ができれば、既に運用されているnode.jsプロダクトへ楽に導入できるし、プロダクトの品質向上につながります。
私と同じように考えている人は多いらしく、本家のissueや、stackoverflowにも幾つか言及がありました。 github.com
Comment Typesを使った型チェック
前述した要望を見たすために、flowは公式にコメントベースでのsyntaxをサポートしています。
このsyntaxを使うことで、pure javascriptのコードを変えずに、クラスプロパティや、関数、メソッド引数の型チェックが可能になります。
babelによるトランスパイルを挟まなくても型チェックを導入できるので非常に便利です。
flow.org
Comment type include
このComment Typesを使う際には、従来のコメントと区別するために、コメントの先頭にダブルコロン「::」を付ける必要があります。
/*:: type Foo = { foo: number, bar: boolean, baz: string }; */ class MyClass { /*:: prop: string; */ }
上記のコードは、pure javascriptであり、従来通り実行が可能です。 flowによる型チェックの際に、以下のような形でインクルードされ、型チェックが行われます。
type Foo = { foo: number, bar: boolean, baz: string }; class MyClass { prop: string; }
ダブルコロンの他に 「flow-include」と記述しても動作します。
/*flow-include type Foo = { foo: number, bar: boolean, baz: string }; */ class MyClass { /*flow-include prop: string; */ }
Comment type annotation
前項のように毎回::やflow-includeを使って書く代わりに、コメントの先頭にシングルコロン「:」を使って楽に書くことができます。
例えば下記のように、関数の引数のあとに追加します。
function concat(a /*: string */, b /*: number*/) { return a + b; } // 引数の型がそれぞれ指定したものと異なっている concat(1, "a")
flowによる型チェックを実行すると
Error: index.js:24 24: concat(1, "a") ^ number. This type is incompatible with the expected param type of 13: function concat(a /*: string */, b /*: number*/) { ^^^^^^ string Error: index.js:24 24: concat(1, "a") ^^^ string. This type is incompatible with the expected param type of 13: function concat(a /*: string */, b /*: number*/) { ^^^^^^ number
ちゃんと型チェックが行われ、エラーを出してくれます。
まとめ
flowによる型チェックは、引数のnullチェックなどちゃんとやってくれるようで非常に強力です。
これを実環境のコードやデプロイフローを変えるなく導入できれば、コードのさらなる品質向上が期待できます。
前述したように、flowはComment Typeで、コメントとして記述する方法もちゃんとサポートされているので、 導入するハードルがかなり下がるので、pure javascriptで書いているプロジェクトは導入する余地がかなりあると思います。