音楽サーバ"Mopidy"のフロントエンドを作る:09 TypeScript用の型定義をつくる、その2
音楽サーバ"Mopidy"のフロントエンド「Mopidy.Finder」が出来るまで、第9回です。
今回も引き続き、TypeScriptでライブラリを使う際の型定義について、です。
@typesにない、だと...
Mopidy.FinderではUIの画面サイズの判定に、BootstrapのためのユーティリティResponsive Bootstrap Toolkit
を使っています。
それを@typeでsearchしてみると...
うへえ。見つかんねえ...
大正義@typesとはいえ、型定義が存在しないライブラリも、あるんですね。
ないなら書けばいいじゃない
そう、定義が無いなら、書けばいいのです。
ゴハンが無いならケーキを食えばいいのです。
めんどくせえよアントワネット!
あら、意外とそうでもありませんですのよ。オホホ。
使うとこだけ、書けばいい
この、Responsive Bootstrap Toolkit
。
欲しい機能は、
- isメソッド: Windowサイズ比較用メソッド
- changedコールバック: Windowサイズ変更時のコールバック
- currentメソッド: 現在のWindowサイズを取得するメソッド
くらいなもんです。
加えて、このライブラリはまだBootstrap4に対応していないため、
- useメソッド: Windowサイズ定義をセットするメソッド
も入れておきます。
別にDefinitelyTyped
リポジトリにプルリクする訳でもなく、自分が使うだけのこと。
それなら、使うところだけを定義しておけばいいのです!
定義の種類
まず定義するに当たって、読み込むライブラリが何者なのかを調べます。
型定義にはおおむね、下の4種類が多く見受けられます。
- newして使う、
クラス
の定義 - 既に生成済みの
インスタンス
の定義 - 各種クラスやインタフェース類、staticメソッドを集めた、
名前空間
としての定義 - staticなメソッドを持ち、かつnewでインスタンスを生成する
クラス
でもある定義。
このうち1.のクラス定義は、クラスベースのTypeScriptでは最も馴染みやすいものです。
declare class [クラス名]
としておき、中身はインタフェースを書く要領でpublicメンバーを書き連ねていきます。
4.の複合型定義は、見かける頻度は高いんですが、書くのはしんどいです。
クラスと名前空間を同じ名前で定義し、staticメソッドやインタフェース定義などを名前空間に集めておく書き方です。
前回記事に挙げたSortableJSの定義が、このように作られています。
そして、冒頭で挙げたResponsive Bootstrap Toolkit
は、どんなものでしょう?
ライブラリの使い方としては、下記のように書いてます。
import * as ResponsiveBootstrapToolkit from 'responsive-toolkit/dist/bootstrap-toolkit'; if (ResponsiveBootstrapToolkit.is('<=md')) { // md以下のときの処理 }
これは、2.のインスタンス
をimportしている、と考えてよいでしょう。
インスタンスの型定義
型定義ファイルで書くdeclare
構文。
これは、そのライブラリをimportしたときに存在するはずのもの、を示しています。
クラスが存在するはずならば、declare class [クラス名]
となります。
Responsive Bootstrap Toolkit
の場合はクラスでなくインスタンスになるため、存在するのは生成済みインスタンスの入れ物になる、変数名です。
この場合は、const/varで宣言された変数をdeclare
します。
declare const ResponsiveBootstrapToolkit;
そして、そのインスタンスが持つべきメンバーを、インタフェースとして定義します。
interface IResponsiveBootstrapToolkit { is(complareString: string): boolean; changed(callback: () => void, waitMsec?: number): void; current(): string; use(framewrokName: string, breadpoints: { [breadkpoint: string]: JQuery }): void; }
declareしたインスタンスは上述のインタフェースを持つため、型を指定してやります。
declare const ResponsiveBootstrapToolkit: IResponsiveBootstrapToolkit;
最後に、このライブラリはモジュールのため、存在宣言した変数をexportしてやります。
export = ResponsiveBootstrapToolkit;
全部合わせて、8行のコードで済みました!
types/responsive-toolkit/index.d.ts:
interface IResponsiveBootstrapToolkit { is(complareString: string): boolean; changed(callback: () => void, waitMsec?: number): void; current(): string; use(framewrokName: string, breadpoints: { [breadkpoint: string]: JQuery }): void; } declare const ResponsiveBootstrapToolkit: IResponsiveBootstrapToolkit; export = ResponsiveBootstrapToolkit;
これで、Responsive Bootstrap Toolkit
が、型安全に使えるようになります!
名前空間、と解釈してみる
このResponsive Bootstrap Toolkit
、生成済みインスタンス
として扱っていますが。
これは、staticなメソッドを持つ名前空間
、として見ることも出来ます。
そのように、書き換えてみたのがこちら。
declare namespace ResponsiveBootstrapToolkit { function is(complareString: string): boolean; function changed(callback: () => void, waitMsec?: number): void; function current(): string; function use(framewrokName: string, breadpoints: { [breadkpoint: string]: JQuery }): void; } export = ResponsiveBootstrapToolkit;
これでも、ビルドは通ります。
ただ、名前空間として考えるには、少し機能が小さすぎますかね?
そのへんは、お好みで。
以上、TypeScriptの型定義づくり、その2でした!