次世代JavaScript系言語「TypeScript」の主要言語機能:特集:TypeScript(プレビュー版)概説(後編)(2/2 ページ)
TypeScriptの基本的な言語仕様をコード例で示しながら解説。今回は「クラスの継承」「インターフェイス」「モジュール」。
モジュール
TypeScriptのモジュール(Module)には、次の2種類がある。
- 内部モジュール(Internal Modules): いわゆる「名前空間(NameSpace)」の役割を持つもので、クラス間に境界線や階層を作ることで、名前の衝突を防いだり、構造を管理しやすくしたりするためのもの。
- 外部モジュール(External Modules): いわゆる「モジュール(=部品)」の役割を持つもので、外部ファイルに記述されたコード本体を、そのファイル名(=外部モジュール名)を使って参照・ロードするためのもの。
以下では、それぞれについてコード例を示しながら説明する。
●内部モジュールの宣言
内部モジュールは「module」というキーワードを使って宣言できる。例えば次のコードは、「Products.Vehicles」という名前(=識別パス)のモジュールを宣言している。
// 識別パス
module Products.Vehicles {
// exportして初めてモジュールの外で使える
export class Bike {
move(speed: number): string {
if (speed > Settings.maxSpeed)
return speed + "km! バイクはスピード違反です。"
else
return "バイクは時速「" + speed + "km」で進んでいます。";
}
}
// 入れ子モジュール
export module Parts { }
// exportしない場合は、モジュール内でのみ使える
class Settings { static maxSpeed = 80; }
}
○exportキーワード
上記のコードで注目してほしいのは、モジュール内のクラスやモジュールに「export」と付いているところだ。これを付けて、外部からアクセス可能であることを明示しなければ、外からそのクラスやモジュールなどにアクセスすることはできない。
exportキーワードを付けていないSettingsクラスは、外部クラスからはアクセスできないが、Bikeクラスのmove関数内に「Settings.maxSpeed」とあるように、モジュール内のクラスからはアクセスできる。
○入れ子(=ネスト)可能
Products.Vehiclesモジュール内にPartsモジュールを定義しているが、内部モジュールではこのように入れ子にして階層を作れる(※一方、クラスは入れ子にできない)。
●内部モジュールの利用
続いて、上記のコードのモジュールを利用する例を示そう。次のコードは、Products.Vehiclesモジュール内のBikeクラスをインスタンス化して、move関数を呼び出している例だ。
……上記のコードの続き……
declare var jQuery: any; // jQueryの型を宣言
jQuery(document).ready(() => {
var vc = Products.Vehicles; // モジュール名が長いので、別の型名を定義
var bk = new vc.Bike(); // 「new Products.Vehicles.Bike()」と同じ
var msg = bk.move(50);
//var pt = Products.Vehicles.Parts; // 入れ子モジュールへのアクセス例
});
上記のコード例では「var vc = Products.Vehicles;」というコードで、モジュールをいったん変数に入れているが、これはそのようなコーディングが可能であることを示すために書いたもので、必ずしもこのように記述する必要はない(通常は「new Products.Vehicles.Bike()」と記述すればよい)。
前述したモジュールの宣言では、Products.Vehiclesモジュールの中にPartsモジュールを入れたが、このような入れ子モジュールにアクセスするには「.」で連結して表現する。この例では「Products.Vehicles.Parts」というコードで入れ子モジュールにアクセスしている。
○外部JavaScriptライブラリの利用(例:jQueryの利用)
上記のコードでは、JavaScriptライブラリの1つである「jQuery」を使っている。このようにTypeScriptでは、外部JavaScriptライブラリを利用することもできる。
「declare var jQuery: any;」というコードは、jQueryという名前のオブジェクトの型が「any」であること(つまり、JavaScriptのオブジェクトであること)を宣言(declare)している。この宣言により、「jQuery(document).ready(() => { ... }」という記述をしても、TypeScript上でエラーにならなくなるというわけだ。このdeclareキーワードによる宣言は、「アンビエント宣言(Ambient Declarations、環境宣言)」と呼ばれる。
なお、当然ながら、次のコード例のようにjQueryのライブラリ自体はHTMLファイル上で読み込む必要がある(そうしなければ、変換後のJavaScriptコードの実行時にエラーが出てしまう)。
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>TypeScript HTML App</title>
<link rel="stylesheet" href="app.css" type="text/css" />
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js "></script>
<script src="app.js"></script>
</head>
<body>
<h1>TypeScript HTML App</h1>
<div id="content"/>
</body>
</html>
○依存関係ソース・ファイルの指定
上記のコードでは、declareキーワードによりjQueryオブジェクトを宣言していたが、そのJavaScriptライブラリが多数のオブジェクトを提供している場合(また、先ほどは「any」だった型をインターフェイスで明確に型定義したい場合)、その全てを宣言しなければならないので、コードが宣言だらけになってしまうという問題がある。
そのような場合、アンビエント宣言(と、その関連のインターフェイス)のみが含まれる宣言ソース・ファイル(Declaration Source Files)を「.d.ts」という拡張子を付けて作成し、それを「/// <reference path="path/to/…….d.ts"/>」という参照コメント形式の「ソース・ファイルの依存関係(Source Files Dependencies)」の指定でTypeScriptコンパイラに読み込ませればよい。具体的には、次のようなコードになる。
/// <reference path="./js/jquery.d.ts" />
……省略……
jQuery(document).ready(() => {
……省略……
});
jQueryの.d.tsファイルは、マイクロソフトによるサンプル・コードの中に含まれているので、今回はそのファイルをプロジェクトの「js」フォルダ内にダウンロードして使用した。
なお、TypeScriptコンパイラは「lib.d.ts」ファイル(具体的には「C:\Program Files\Microsoft SDKs\TypeScript\lib.d.ts」)を自動的に参照する。このファイルは、ビルトインのJavaScritpライブラリやDOM(Document Object Model)関連の宣言が含まれている。このおかげで、上記のコードにある「document」などのDOMオブジェクトにもTypeScriptコード上でアクセスできる。
○外部ファイルのクラスへのアクセス
依存関係の指定では、.d.tsファイルだけでなく、.tsファイルも参照できる。例えば「utils.ts」というファイルを独自に作成して(TypeScript用のファイルを正確に作成するには、[ソリューション エクスプローラー]のプロジェクト項目の右クリック・メニューで[追加]―[新しい項目]を選択すると表示されるダイアログで、必ず「TypeScript File」テンプレートを選択する)、次のようなモジュールを実装したとしよう。
module Utils {
export class MessageBox {
static show(s: string) {
alert(s);
}
}
}
このファイルを先ほどの依存関係の指定と同じ方法で指定すればよい(次のコードを参照)。
/// <reference path="./utils.ts" />
declare var jQuery: any;
jQuery(document).ready(() => {
// 外部ファイルのモジュール内のクラス・メンバにアクセス!
Utils.MessageBox.show("外部ファイル!");
});
そして、最終的なJavaScriptファイル(この例では「utils.js」)が実行時に読み込まれるように、HTMLファイル内に「<script src="utils.js"></script>」を書き加えればよい。
●外部モジュールの2つのパターン
先ほどの外部ファイルの例では、JavaScriptファイルを「静的に」読み込んでクラスなどの機能を使っていた。しかしJavaScriptライブラリが増えてきて「動的に」読み込みたいニーズが出てきたときや、Node.jsのようなサーバサイド・フレームワークで別のJavaScriptファイルをロードしたいときには、「外部モジュール」という機能を使う必要がある。
外部モジュールについてもう一度簡単に説明すると、「外部ファイルに記述されたコード本体(=モジュール)を、そのファイル名(=外部モジュール名)を使って参照・ロードするためのもの」である。
外部モジュールは、次の2種類のJavaScript上の実装パターンで提供されており、コンパイラ・スイッチによりどちらのパターンでモジュールを生成するかを指定できる。
- CommonJS準拠モジュール: 既定のパターン。主にNode.jsのようなサーバサイドで利用する。Node.jsのrequire関数などを使うことで、(CommonJS準拠の)モジュールを動的にロードできる。
- AMD準拠モジュール: AMDは「Asynchronous Module Definition(非同期モジュール定義)」の略語。主にブラウザなどのクライアントサイドで利用する。RequireJSなどのAMD対応JavaScriptライブラリを使うことで、モジュールを動的にロードできる。
本稿では、Node.jsは使っていないので、AMDモジュール・パターンを使うことを前提として、外部モジュールを説明する。
●外部モジュールの実装
外部モジュールを実装するには、.tsファイルを作成して、その中に内部モジュールやクラスを実装する。次のコードはその例だ(この例では「amdUtils.ts」ファイルを作成した)。
export class MessageBox {
static show(s: string) {
alert(s);
}
}
ここでのポイントは、クラスの前に「export」キーワードが付いていることだ。モジュールの外から、内部のクラスやモジュールにアクセスしてもらうには、この指定が欠かせない。
●外部モジュールの利用
次に、外部モジュールをロードする側の.tsファイル(この例では「app.ts」)に、次のようにモジュールをインポート(import)するコードを記述する。
/// <reference path="./js/jquery.d.ts" />
import amdVar = module("amdUtils"); // 外部モジュールをインポート
jQuery(document).ready(() => {
amdVar.MessageBox.show("外部モジュールの関数にアクセス!");
});
ここでのポイントは、「import」キーワードで変数(この例では「amdVar」)を宣言し、「module('path/to/module')」というコードで読み込み対象のモジュールを指定していることだ。
この例では、「amdUtils」という外部モジュール名が指定されているが、これは上記の「amdUtils.ts」というファイル名から拡張子を省略したものだ。このように外部モジュール名の.ts/.js拡張子は(基本的に)省略する。また、この例では同じフォルダにある外部ファイルを指定しているので、パスの部分は指定していないが、「../js/amdUtils」のような相対パスや、「C:/Libs/ui/utils.ts」のような完全パスも指定できる。
●AMDモジュール・パターンにおけるRequireJSの利用
以上で外部モジュールの実装は完了だが、仕上げとしてRequireJSの利用をHTMLファイル上に記述しなければならない。今回は、CDN(コンテンツ配信ネットワーク)で提供されている「require.min.js(バージョン2.1.1)」を使うことにしよう。具体的には次のようなコードになる。
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>TypeScript HTML App</title>
<link rel="stylesheet" href="app.css" type="text/css" />
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js "></script>
<script data-main="app" type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.1/require.min.js"></script>
</head>
<body>
<h1>TypeScript HTML App</h1>
<div id="content"/>
</body>
</html>
上記のコードでは<script>タグでRequireJSライブラリを読み込んでいる。そのdata-main属性に「app」と指定されているが、これにより(app.tsファイルから変換された)app.jsファイルが実行されることになる。
●AMDモジュール・パターンでコンパイルするための設定
前述したように、既定ではCommonJSモジュール・パターンでコンパイルされるので、AMDモジュール・パターンでコンパイルされるように「--module amd」というコンパイラ・スイッチを指定する必要がある。
Visual Studio 2012のIDEでビルドする場合は、プロジェクト・ファイル(今回の例では「FirstTypeScriptHTMLApp.csproj」ファイル)をテキスト・エディタなどで開き、
<Exec Command="tsc$(TypeScriptSourceMap) @(TypeScriptCompile ->'"%(fullpath)"', ' ')" />
というコードを、
<Exec Command="tsc$(TypeScriptSourceMap) @(TypeScriptCompile ->'"%(fullpath)" --module amd', ' ')" />
と書き換えると(具体的には「 --module amd」を追記すると)、正常にビルド&実行できるようになる。
以上、TypeScriptの基本的な言語機能について説明した。これからジェネリックなどの重要機能が追加される予定なので(参考:「TypeScript Roadmap(英語)」)、本格的に実用するにはまだ早いと思うが、今からプロトタイプなどを作成してTypeScriptの可能性を試すのは悪くないだろう。実際にコードを見て学ぶのが一番速いと思うので、本稿の次はCodePlexサイト上で提供されているサンプル・コードをダウンロードしていろいろ試してみてほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.