Mapboxの非表示シンボルを扱う (3. 型の拡張編)
2022-09-24
Mapbox GL JSの画面上で別のシンボルに隠されたシンボルを扱うユーティリティライブラリを開発中です。 これはライブラリの開発過程を紹介するシリーズのブログ投稿第3弾です。
背景
本シリーズの過去の2回の投稿で以下を示しました。
このブログ投稿では、Mapbox GL JS (mapbox-gl-js
)のいくつかの型がTypeScriptで利用できないという残課題に挑みます。
ライブラリ(mapbox-collision-boxes
)は私のGitHubレポジトリで手に入ります。
TypeScript?
TypeScriptはJavaScriptの亜種で、強力な型機能を提供します。
詳しくはTypeScriptの公式ウェブサイトを参照ください。
このページ[1]はTypeScriptとJavaScriptの違いを理解するのに役立ちます。
mapbox-collision-boxes
の実装言語にはTypeScriptを選択しました。
mapbox-gl-jsには型が定義されているのか?
答えは「はい」ですが、mapbox-gl-js
はJavaScriptに型を導入する別の流儀であるFlowで型を定義しています。
残念ながら、Flowの型定義はTypeScriptと互換性がありません。
なのでmapbox-gl-js
の外側にTypeScriptの型定義が必要です。
TypeScriptコミュニティのコントリビュータさんが頑張ってくださっているおかげで、これらの型は@types/mapbox-gl
*として利用することができます。
* このブログを書いているときの@types/mapbox-gl
の最新バージョンは2.7.5で、これはmapbox-gl-js
バージョン2.7をベースにしています。
当時のmapbox-gl-js
の最新版は2.10ですが、バージョンの違いによる問題にはとりあえず遭遇していません。
@types/mapbox-glが欠いているもの
@types/mapbox-gl
はmapbox-collision-boxes
が依存しているいくつかのプロパティや型を公開していません。
たとえば、Map
クラス(@types/mapbox-gl/index.d.ts#L201-L602)はstyle: Style
プロパティを欠いています。
@types/mapbox-gl
はBucket
クラスもSymbolBucket
も定義していません。
どう対処するか?
型チェックを諦めるというのに惹かれるかもしれませんが、これは最終手段です。
mapbox-gl-js
の既存の型定義を拡張するにはモジュール拡張(Module Augmentation)を使うことができます。
「モジュール拡張」はTypeScriptの少し踏み込んだ機能です。
詳しくはTypeScriptのドキュメントの参照ください。
たとえば、以下のスニペットはMap
クラスにstyle: Style
プロパティを追加します。
;
上記の宣言の後は、Map#style
に型安全にアクセスできます。
Bucket
とSymbolBucket
については、単純に@types/mapbox-gl
に存在していないのでインターフェイスを追加するだけで良いです。
指定したBucket
がSymbolBucket
かどうかをチェックするユーティリティ関数(mapbox-collision-boxes/private/mapbox-types.ts#L232-L234)も導入しました。これはTypeScriptの「型述語(Type Predicates)」という機能を利用しています。
mapbox-collision-boxes
を実装するのに最低限必要な定義は私のGitHubレポジトリにあります。
まとめ
今回の短い投稿では、以下のTypeScriptの機能を紹介しつつmapbox-gl-js
の既存の型(@types/mapbox-gl
)をどうやって拡張するかを示しました。
mapbox-collision-boxes
は私のGitHubレポジトリで手に入ります。
参考
- TypeScript for the New Programmer - https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html (TypeScriptとJavaScriptの違いを理解する)