はじめに
HERE Maps API for JavaScript は、React アプリに地図を組み込む際の有力な候補の一つです。
こちらの実装の際、公式の「React Practices」に沿って <script> タグでHEREマップを読み込むのが一般的ですが、この構成に型定義を加えることで、開発体験を向上させていきます。
直面する課題:標準では型が効かない
公式推奨の「Script タグでの読み込み」はパフォーマンスに優れる反面、npm パッケージを import する方法とは勝手が異なります。そのため、TypeScript 環境下であってもグローバルオブジェクト H が認識されず、標準状態では型定義の恩恵を受けることができません。
結果として、コード内で any 型を使用せざるを得なかったり、メソッドの引数や戻り値が不明確なまま実装を進めることになり、開発効率や保守性が低下してしまいます。
本記事の目的
そこで本記事では、公式推奨の実装パターンを維持しつつ、TypeScript の型安全性を確保するための手順を解説します。
具体的には以下の設定を行います。
-
@types/heremapsの導入: 基本的なクラスやメソッドの型情報を利用可能にする - 型定義の拡張: 公式の型定義に含まれていない機能(v3.2の新機能など)に対して、不足している型定義を追加(マージ)する
これにより、React × TypeScript 環境において、HERE Maps API をスムーズかつ安全に実装できる環境を構築します。
環境
- React
- TypeScript
- HERE Maps API for JavaScript v3.2
導入手順
1. ベースの型定義をインストール
コミュニティベースの型定義を導入し、基本クラス(H.Map, H.service.Platform 等)の型を確保します。
npm install --save-dev @types/heremaps
2. 型定義の拡張
@types/heremaps に含まれていない最新機能(v3.2のHARPエンジン設定など)や、不足しているオプション引数を補うため、独自の型定義ファイルを作成します。
既存の型を上書きするのではなく、TypeScript の「宣言マージ」機能を利用して差分のみを定義していきます。
// 既存の H 名前空間に、足りない型定義のみを「マージ」させます
declare namespace H {
namespace Map {
// エンジンタイプ定数の型を追加
const EngineType: {
HARP: number;
WEBGL: number;
};
}
namespace map {
// 2. まるごと存在しない名前空間 (render.harp) を新規定義
namespace render {
namespace harp {
class Style {
constructor(url: string);
addEventListener(
type: string,
handler: (event: StyleEvent) => void,
options?: { once: boolean }
): void;
getEnabledFeatures(): Array<StyleFeature>;
setEnabledFeatures(features: Array<StyleFeature>): void;
}
interface StyleEvent {
target: Style;
}
interface StyleFeature {
feature: string;
mode: string;
}
}
}
}
// 必要に応じて他の名前空間も拡張可能
namespace service {
namespace omv {
class Provider {
constructor(
service: H.service.Service,
style: H.map.render.harp.Style,
options?: { engineType?: number; lg?: string }
);
}
}
}
}
3. tsconfig.json の確認
作成した d.ts ファイルがコンパイラに認識されているか確認します。
通常は include に含まれていれば自動で読み込まれます。
{
"compilerOptions": {
"types": ["heremaps"]
},
"include": ["src/**/*"]
}
実装例 (React)
上記の設定を行うと、以下のように型安全な状態で地図コンポーネントを実装できます。
import React, { useLayoutEffect, useRef } from 'react';
export const MapComponent = () => {
const mapRef = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
if (!mapRef.current) return;
// グローバルな H が型付きで認識される
const platform = new H.service.Platform({
apikey: 'YOUR_API_KEY'
});
const defaultLayers = platform.createDefaultLayers();
// 拡張した型 (engineType) も補完が効く
const map = new H.Map(
mapRef.current,
defaultLayers.vector.normal.map,
{
zoom: 10,
center: { lat: 35.689, lng: 139.692 },
engineType: H.Map.EngineType.HARP // カスタム定義した定数
}
);
// ...後略
return () => {
map.dispose();
};
}, []);
return <div ref={mapRef} style={{ height: '500px' }} />;
};
まとめ
v3.1 から v3.2 (HARP エンジン) への移行のようなケースでは、@types/heremaps をベースにしつつ、不足分を Declaration Merging で補うアプローチが非常に有効でした。これにより、開発コストを低く抑えつつ、最新機能への追従が可能になります。
React × HERE Maps 開発における「型定義の悩み」を解決する一つの手段として、本記事が役立てば幸いです。