パラメーター調整用のJavaScriptライブラリ「Tweakpane」について、FlowからTypeScriptに全面移行したので、その理由と所感を。
JavaScriptは明示的な型を持たないプログラミング言語です。コードを気軽に書き捨てられる寿命の短い案件ならそれでも問題ないのですが、大規模かつ長期的に保守運用するプロジェクトには正直不向きでしょう。
JavaScriptに型を導入するための選択肢として挙がるのがFlowあるいはTypeScriptですが、それぞれアプローチが異なっています。
FlowはFacebookの主導するプロジェクト。素のJavaScriptをベースに、型情報を付加できるように拡張した記法です。
“Flow is a static type checker for JavaScript” と謳うとおり、基本的にはJavaScriptであり、公式のツールを利用すれば型情報を取り除いてプレーンなJavaScriptに戻せるのがポイントです。
もう一方のTypeScriptは、Microsoftが主導するプロジェクト。
“TypeScript is a typed superset of JavaScript that compiles to plain JavaScript” とあるとおり、JavaScriptを拡張した別言語という位置づけで、コンパイルした結果としてJSファイルを得ることができます。
個人的には、TypeScriptは数年前に触れたあとしばらく縁がなく、最近業務でお手伝いしているプロジェクトではFlowを本格的に利用している状況でした。Flowを辞めるほどの致命的な理由もなくここまで使ってきましたが(小さな問題点はたくさんある)、ある日流れてきたアンケート結果を見て先行きに不安を感じはじめます。2枚目の画像に注目。
1枚目 #nodefest
— Sakito (@__sakito__) December 8, 2018
2枚目 #html5j
3枚目 #Designship2018
4枚目 #fec_fukuoka
最近あったカンファレンスのアンケート集計結果!🎉
これ持ってるのわいだけなのでは🤔🤔 pic.twitter.com/5m09aHjLXu
Flowの利用者がそれほど多くないことは承知していたものの、既存ユーザーの評判もこれほどまでに悪いとは…。
試しにGoogleのトレンドを調べてみると、こちらも定常的にTypeScriptが優位のようで、前述した印象とも合致します。
TypeScriptは昔使っていたときにいろいろと苦しめられた思い出があるのですが、過去の体験に固執していてはあっという間に老害です。あれから数年、FlowとTypeScriptの違いは現状どんなもんだろう?
進化したであろうTypeScriptもしっかりキャッチアップしておかねばと思い、個人のOSSプロジェクトでFlow→TypeScriptの乗り換えを試してみることにしました。
涙ぐましい移行の痕跡がこちら。
先にまとめておくと、既存のコードおいてはFlowもTypeScriptも大差なく、頭を使うような書き換えはほとんどなかったものの、純粋に変更量が多く物理(筋肉)的な理由でとても疲れました。
書き換え対象 | Flow | TypeScript |
---|---|---|
構造的型の定義 | type Foobar = {...}; | interface Foobar {...} |
null許容型 | ?string | string | null | undefined |
不明な型(型安全) | mixed | unknown |
読み取り専用のフィールド | +field: string; | readonly field: string; |
明示的な型指定 | (foobar: any) | (foobar as any) |
文字列リテラルの共用体型をキーとするオブジェクト | {[Foobars]: string} | {[key in Foobars]: string} |
関数の戻り値の型 | $Call<...> | ReturnValue<...> |
よほどディープな使いかたをしていなければ、型の表現力自体はそれほど変わらないように感じました。
昔のTypeScriptを振り返ると、nullの扱いが緩かったり、テスト実行やカバレッジ計測の際には一時的にJavaScriptに変換する必要があったりと、面倒な落とし穴が散在していました。しかしながら、その後のアップデートでnullチェックも強化されていますし、実行に関してはts-nodeを使えば一時ファイルも不要になっており、結果的には大きな面倒なく移行できました。
むしろ依存関係が簡素化されたこと、minify後のファイルサイズも小さくなった(こちらは意図せぬ効果であり一般的かは疑問)こともあり、当プロジェクトに関してはひとまず移行してよかったという結論になりました。
今回の移行の所感をまとめると…
せっかく型を導入した世界でコードを書いているので、npmのパッケージとして広く公開する場合は、利用者側にも型情報を活用してほしいものです。TypeScriptにはそのための仕組みが用意されており、具体的には以下の手順で実現できました。
compilerOptions
に declaration: true
を追加して、型情報ファイル(d.ts)を出力させるtypes
を追加し、メインとなるd.tsのパスを指定する詳細は、公式ドキュメントの「Publishing · TypeScript」に記載されています。