TypeScriptの練習をかねて,OpenLayersを使っているJavaScriptをTypeScriptにしてみる実験です.※最新版のTypeScript定義は,GitHub でメンテしています.

TypeScriptについての説明は省略します.TypeScriptのセットアップ(Windows XP)は,以下の手順で行いました.

(1) node.jsをインストールする
http://nodejs.org/
node-v0.10.12-x86.msi をダウンロードして実行

(2) コマンドプロンプトから
npm install -g typescript
を実行する

ソース

以下のhtmlとtsファイルを準備します.普通にOpenLayersを使って地図を表示して, マーカーを
LonLat(135.220825,34.796897)
の位置(神戸電鉄 有馬口駅)に表示するスクリプトです.

0627-1.jpg

test.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js" charset="UTF-8"></script>
<script type="text/javascript" src="test.js" charset="UTF-8"></script>
</head>
<body onload="init()">
<div id="map" style="width:400px;height:400px;"></div>
</body>
</html>

次のファイルは拡張子がtsですが,見ての通り実体はJavaScriptです.先頭にreference pathが付いているという違いだけです.

test.ts

/// <reference path="openlayers.d.ts" />

var proj900913 = new OpenLayers.Projection("EPSG:900913");
var proj4326 = new OpenLayers.Projection("EPSG:4326");

var msize = new OpenLayers.Size(25, 35);
var moffset = new OpenLayers.Pixel(-(msize.w/2), -msize.h);
var icon = new OpenLayers.Icon('http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=S|B0B0FF|000000',
		msize, moffset);

function init() {
	var applyZoomLv = 15;
	var maxExtent = new OpenLayers.Bounds(-20037508, -20037508, 20037508, 20037508);
	var restrictedExtent = maxExtent.clone();
	var maxResolution = 156543.0339;
	var mapOptions = {
		controls: [
			new OpenLayers.Control.Navigation({mouseWheelOptions: {interval: 100}}),
			new OpenLayers.Control.PanZoomBar(),
			new OpenLayers.Control.KeyboardDefaults(),
			new OpenLayers.Control.Attribution()
		],
		projection: proj900913,
		displayProjection: proj4326,
		units: "m",
		maxResolution: maxResolution,
		maxExtent: maxExtent,
		restrictedExtent: restrictedExtent
	};
	var map = new OpenLayers.Map('map', mapOptions);

	map.addControl(new OpenLayers.Control.ScaleLine(
		{maxWidth:150, bottomOutUnits: "", bottomInUnits: "", geodesic:true}));

	var osmMap = new OpenLayers.Layer.OSM();
	map.addLayer(osmMap);

	// marker setting
	var markerPos = new OpenLayers.LonLat(135.220825,34.796897)
		.transform(proj4326, proj900913);

	var markers = new OpenLayers.Layer.Markers("Markers");
	markers.addMarker(new OpenLayers.Marker(markerPos, icon));
	map.addLayer(markers);

	map.setCenter(markerPos, applyZoomLv);
}

次は,先ほどのreference pathで参照していた,OpenLayersのTypeScript定義ファイルです. OpenLayersのAPIドキュメント を見ながら,今回使っている必要最小限だけ定義しました. (本当はもっといい書き方があるかも知れません)

openlayers.d.ts 〜今回の必要最小限のみ

declare module OpenLayers {
	class Bounds {
		constructor(left: number, bottom: number, right: number, top: number);
		clone(): Bounds;
	}
	class Control {
	}
	module Control {
		class Navigation extends Control {
			constructor(options: any);
		}
		class PanZoomBar extends Control {
		}
		class KeyboardDefaults extends Control {
		}
		class Attribution extends Control {
		}
		class ScaleLine extends Control {
			constructor(options: any);
		}
	}
	class Icon {
		constructor(url: string, size: Size, offset: Pixel);
	}
	class Layer {
		addMarker(marker: Marker): void;
		removeMarker(marker: Marker): void;
	}
	module Layer {
		class Markers extends Layer {
			constructor(name: string);
		}
		class OSM extends Layer {
		}
	}
	class LonLat {
		constructor(lon: number, lat: number);
		transform(source: Projection, dest: Projection): LonLat;
	}
	class Map {
		constructor(div: string, options: _MapOptions);
		addControl(controls: Control, px?: Pixel): void;
		addLayer(layer: Layer): void;
		setCenter(lonlat: LonLat, level?: number);
	}
	interface _MapOptions {
		controls: Control[];
		projection: Projection;
		displayProjection: Projection;
		units: string;
		maxResolution: number;
		maxExtent: Bounds;
		restrictedExtent: Bounds;
	}
	class Marker {
		constructor(lonlat: LonLat, icon: Icon);
		icon: Icon;
	}
	class Pixel {
		constructor(x: number, y: number);
	}
	class Projection {
		constructor(projCode: string);
	}
	class Size {
		constructor(width: number, height: number);
		w: number;
		h: number;
	}
}

この3ファイルが揃ったら,コマンドプロンプトからtscでコンパイルしてみます.

C:\work\TypeScript>tsc test.ts

すると,test.js が出力されますので,ブラウザでtest.htmlを開くとそのjsを読み込んで地図が出ます.

TypeScriptを使う利点

これだけ見ると,こんなことをして一体何が嬉しいのか?となるかも知れません.

利点としては,ブラウザで実行しなくてもコンパイル時にエラーチェックができるということだと思います.

例えば,test.tsでnew OpenLayers.Map()に渡しているmapOptionsを,

units: "m",
ではなく
unit: "m",
に間違えたとします.

すると,コンパイルで以下のようにエラーになります.

C:\work\TypeScript>tsc test.ts
C:/work/TypeScript/test.ts(30,27): error TS2082: Supplied parameters do not match any signature of call target:
  Type '{ controls: OpenLayers.Control.Attribution[]; projection: OpenLayers.Projection; displayProjection:
  OpenLayers.Projection; unit: string; maxResolution: number; maxExtent: OpenLayers.Bounds; restrictedExtent:
  OpenLayers.Bounds; }' is missing property 'units' from type 'OpenLayers._MapOptions'.
C:/work/TypeScript/test.ts(30,27): error TS2085: Could not select overload for 'new' expression.

ブラウザで実行する前に,このように打ち間違いを排除できるのは,私は嬉しいですね (´∀`)

...後で気がつきましたが,これはあまり良くない例です.

unitsは別に必須ではないので,他の用途も想定すると,openlayers.d.ts の記述は

interface _MapOptions {
	・・・
	units?: string;
	・・・
}
という省略可能の定義になると思います.

しかしそうすると,unitsの記述間違いのチェックはできなくなります.

jQueryのTypeScript定義でも,似たような問題というか限界があるようです.

参考

kamolandをフォローしましょう


© 2021 KMIソフトウェア