Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
連載:Visual StudioユーザーのためのTypeScript入門(2)

連載:Visual StudioユーザーのためのTypeScript入門(2)

Visual StudioとTypeScriptでJavaScriptライブラリを活用する

2014年7月8日

TypeScriptでは大半のJavaScriptライブラリをすぐにそのまま活用できる。Visual Studioで手軽に使う方法や、独自のJavaScriptライブラリを使えるようにする方法を説明する。

株式会社グラニ 沢渡 真雪
  • このエントリーをはてなブックマークに追加

 前回はVisual Studio 2013でTypeScriptを利用した開発を始めるにあたっての導入やVisual Studioの基本機能について簡単に触れたが、今回は実際にアプリケーションを開発する上で必要となるであろう既存のJavaScriptライブラリをTypeScriptから利用する方法について解説する。

TypeScriptからJavaScriptのライブラリを利用するには

 まず「TypeScriptからJavaScriptのライブラリを扱うことができるのか?」という疑問があるかもしれないが、TypeScriptはJavaScriptのライブラリとの相互運用についてきちんと考えられている。

 そもそもJavaScriptは静的な型付けではないため、TypeScriptから見るとJavaScriptのライブラリが提供する型や公開している変数があるかどうか、といったことがそのままでは分からない。例えばjQueryを読み込むと$変数が公開されて利用できるようになるが、TypeScriptは$というものがあるのか、$が何かということについては知らない。つまり何も考えずに$を参照しようとしても、コンパイルエラーとなるわけだ(図1)。

図1 型が定義されていない場合にVisual Studio上でエラーとなる
図1 型が定義されていない場合にVisual Studio上でエラーとなる

 そこでTypeScriptには、「型定義ファイル」と呼ばれる型情報のみを記述したスクリプトファイルを参照する仕組みが用意されている。型定義ファイルは通常、「.d.ts」という拡張子を持ち、内容は通常のTypeScriptのコードとほぼ同じだ。違いは、「実装のコードはなく宣言のみ」という点である。

 以下はjQueryの型定義ファイル(jquery.d.ts)の一部を抜粋したものである。

TypeScript
……略……
/**
* Static members of jQuery (those on $ and jQuery themselves)
*/
interface JQueryStatic {

  /**
   * Perform an asynchronous HTTP (Ajax) request.
   *
   * @param settings A set of key/value pairs that configure the Ajax request. All settings are optional. A default can be set for any option with $.ajaxSetup().
   */
  ajax(settings: JQueryAjaxSettings): JQueryXHR;

  ……略……
}

declare module "jquery" {
  export = $;
}

declare var jQuery: JQueryStatic;
declare var $: JQueryStatic;
リスト1 jQueryの型定義ファイル(jquery.d.ts)の一部抜粋

 このファイルを参照することによって、TypeScriptのコンパイラーは外部のコードで$が宣言されていて、jQueryStaticインターフェースのメンバーを持つということを理解し、利用できるようになる。

 型定義ファイルは自由に作成し参照できるため、ライブラリを利用したいときには基本的に型定義ファイルを用意することとなる。

 また型定義ファイルの利点は、コンパイルできるようになるといったことだけなく、Visual StudioのようなIDEがコード補完できるようになったり、シグネチャの説明などのドキュメントコメントを表示できるようになったり(図2)、といった恩恵を受けられることだ。

図2 型定義を参照して変数やクラス、メンバーなどを解決できている
図2 型定義を参照して変数やクラス、メンバーなどを解決できている

DefinitelyTypedとは

 型定義ファイルがあればTypeScriptからJavaScriptのライブラリを利用できることを説明したが、では「ライブラリを使うたびに型定義ファイルを作成しなければいけないのか」というと、それはないので安心してほしい。

 GitHub上に「DefinitelyTyped」というさまざまなライブラリの型定義ファイルをまとめているリポジトリがある。完全にコミュニティ主導のリポジトリであるが、事実上、TypeScript公式に近い位置付けとして見られている。

 jQueryやAngularJS、Backbone.jsのような世界中で定番のライブラリから、flipSnap.jsのような日本発のライブラリまで型定義ファイルがある。そもそもjQueryのような巨大なライブラリの型定義ファイルは作ろうと思ってもなかなか作れるものではないし、大抵のメジャーなライブラリであればDefinitelyTypedに存在するのでTypeScriptを利用する上では必ず世話になるだろう。

 もし、自分が使いたいライブラリの型定義ファイルがない場合や古くなっている場合には、型定義ファイルを作成してPull Requestを送ることにより、取り込んでもらうこともできる。

Visual Studioで型定義ファイルを追加する

 TypeScriptには型定義ファイルという仕組みとそのリポジトリであるDefinitelyTypedがあることについてはざっくりと理解できたと思うが、それらをVisual Studioから活用するにはどうすればよいのかについて紹介したい。

 型定義ファイルはあくまでスクリプトファイルであるので、「GitHubからリポジトリをcloneしたり、Rawでテキストデータを直接ダウンロードすることで入手し、参照を追加する……」といった方法でももちろん活用できる。しかしTypeScriptの新規プロジェクトを始めた直後や、ASP.NETのプロジェクトで利用しているといった場合には、もっと簡単な方法で追加できる。

NuGetで型定義ファイルを追加する

 Visual Studioには「NuGet」と呼ばれるパッケージマネージャーが組み込まれているが(図3)、DefinitelyTypedにあるTypeScriptの型定義ファイルはNuGetのパッケージとして登録されている。TypeScriptの型定義ファイルもVisual StudioのNuGetパッケージマネージャーを利用して簡単に追加できる。

図3 NuGetパッケージマネージャー

 NuGetパッケージで型定義ファイルをインストールするには、NuGetパッケージマネージャーの検索でライブラリの名前に加えて、「DefinitelyTyped」というキーワードを追加することで見付かる。jQueryの型定義ファイルを追加する例を、以下に示す。

DefinitelyTypedにある型定義ファイルをプロジェクトに追加する手順(NuGet利用)

 まずソリューションエクスプローラーからTypeScriptプロジェクトのコンテキストメニューを表示し、[NuGet パッケージの管理]を選択し(図4)、NuGetパッケージマネージャーを開く。

図4 ソリューションエクスプローラーのコンテキストメニューからNuGetパッケージの管理を開く
図4 ソリューションエクスプローラーのコンテキストメニューからNuGetパッケージの管理を開く

 NuGetパッケージマネージャーが開かれたら、右上にある検索ボックスに「jquery DefinitelyTyped」というキーワードを入力して検索する(図5)。

図5 NuGet パッケージの管理で検索する

 その検索結果として「jquery.TypeScript.DefinitelyTyped」というパッケージが見付かるので、パッケージを選択して[インストール]ボタンをクリック。すると、インストールが開始される(図6)。

図6 パッケージをインストールしている様子
図6 パッケージをインストールしている様子

 インストールが完了すると、プロジェクトに「Scripts」フォルダーの下に「typings」フォルダーが作成され、「jquery.d.ts」というファイルが追加される。

図7 パッケージで型定義ファイルがプロジェクトに追加される
図7 パッケージで型定義ファイルがプロジェクトに追加される
JavaScriptファイル名からDefinitelyTypedにある型定義ファイルを検索する方法

 型定義ファイルを検索する方法として、NuGetパッケージマネージャーでキーワードを入力する方法を紹介したが、それ以外の方法として、既存のJavaScriptファイルの名前から簡単に検索こともできる。

 ソリューションエクスプローラー(上のTypeScriptプロジェクト)で、型定義ファイルを検索したいJavaScriptファイルを右クリックしてコンテキストメニューを開くと[TypeScript 型指定の検索]というメニューがあるので(図8)、それを選択することでNuGetパッケージマネージャーが開かれ、すぐに検索できる。

図8 JavaScriptのファイルから型定義ファイルを検索する
図8 JavaScriptのファイルから型定義ファイルを検索する

コードから型定義ファイルを参照する

 NuGetでプロジェクトに型定義ファイルを追加したが、そのままではまだコードからは利用できない。そこで次にコードから型定義ファイルを参照する記述を追加する。

 型定義ファイルの参照の追加は、TypeScriptのソースコードファイルに特別なコメントを追加することで行える。以下はjQueryの型定義ファイルを参照するための記述である。

TypeScript
/// <reference path="scripts/typings/jquery/jquery.d.ts" />
リスト2 jQueryの型定義ファイルを参照するための記述

 型定義ファイルを参照するためのコメントは///(=スラッシュ3つ)で開始し、<reference path="型定義ファイルのパス" />をソースコードの先頭に記述することで、コンパイラーやVisual Studioが認識する。なお、パスの指定はその参照元となるTypeScriptのソースコードからのパスとなる点に注意してほしい。

 Visual Studioでは、この型定義ファイル参照用のコメント挿入を簡略化するための方法が用意されている。挿入するにはまず、参照元のソースコードを開いておき、ソリューションエクスプローラーから型定義ファイルをドラッグし、ソースコードの上にドロップすることで、参照のためのコメントがソースコードに挿入される(図9)。特に理由がない場合には、この方法を使って参照用のコメントを挿入するのが簡単かつ間違いも起きにくいと思われる。

図9 Visual Studioで参照用のコメントを追加

 参照のコメントを追加すると、問題なくjQueryの各種メソッドなどをソースコード上で利用できるようになっていることが確認できる。コード補完なども行われるようになるので(図10)、ぜひ試してほしい。

図10 Visual StudioでjQueryのコード補完が表示されている例

 なお、当然のことではあるが、TypeScriptから型定義ファイルを参照しただけでは実際のライブラリのファイルは読み込まれないため、HTMLソースに<script>要素を書くなどの、ライブラリを読み込むための記述は別途必要である。

型定義ファイルを書く

 ここまでは、既存の型定義ファイルをVisual Studioで参照し、利用するための方法について紹介してきた。しかしながらプライベートのライブラリやDefinitelyTypedの型定義ファイルが古いなど、場合によっては既存の型定義ファイルが存在していない場合もあるため、その書き方について簡単に説明する。

型定義ファイル(=.d.tsファイル)の内容とは

 以前にも触れた通り、型定義ファイルの内容は、「実装のコードはなく宣言のみ」、つまり「このようなメンバーを持つクラスが定義されている」「変数が定義されている」というものである。IDLをご存じの方はそれに似たものだと思うと分かりやすいのではないだろうか。

 宣言は「アンビエント宣言」と呼ばれ、declareという修飾子をクラス定義や変数定義に付けることで、「そのクラスや変数は外部で定義されている」ということを表すことができる。例えば次のような形となる。

TypeScript
// JavaScriptのコードでhogeという変数が定義されている
declare var hoge: number;

// JavaScriptのコードでクラスHogeとメソッドfooが定義されている
declare class Hoge {
  foo(): void;
}
リスト3 アンビエント宣言を用いた型定義ファイルの例(Hoge.d.ts)

TypeScriptコードから独自のJavaScriptライブラリを参照する

 それでは、JavaScriptライブラリのコードをTypeScriptから呼び出す例で説明していく。

プロジェクトの作成とJavaScriptライブラリファイルの作成

 まず、Visual Studioで新規にTypeScriptプロジェクトを作成する。自動で生成されるapp.tsファイルのコード内容は全て削除しておこう。以下のコードを「sample.js」というファイル名でプロジェクトのルートに追加する。

JavaScript
// Personクラス
function Person(name) {
  this.name = name;
}
// Personクラスのsayメソッド(文字列を受け取る)
Person.prototype.say = function (message) {
  alert(this.name + ': ' + message);
}

// Aliceという名前のPersonクラスのインスタンスがグローバルに公開
var Alice = new Person('アリス');
リスト4 JavaScriptライブラリのコード(sample.js)
JavaScriptライブラリに対応する型定義ファイルの作成

 次に、空の型定義ファイルを作成する。

 ライブラリの型定義ファイル名の拡張子は慣習的に「.d.ts」とすることが多いので、ここでは「sample.d.ts」という名前でファイルを作成する。なお、型定義ファイルの新規作成は、[新しい項目の追加]ダイアログからTypeScriptファイルを選択して行う。また、ソリューションエクスプローラーのコンテキストメニューから[追加]で[TypeScript ファイル]を選んで、「filename.d.ts」などのファイル名を入力して作成することもできる。

TypeScriptコードから型定義ファイルへの参照

 最後に、sample.d.tsファイルへの参照を、app.tsファイル(=TypeScriptコード)に追加しよう。

 ここまででVisual Studio上では図11のような構成になっているはずだ。

図11 プロジェクトのファイル構成

TypeScriptから変数を見えるようにする

 それでは最初にまず、グローバルに公開されている変数にアクセスできるよう、型定義ファイル内にAlice変数をany型で定義する。

TypeScript
declare var Alice: any;
リスト5  any型でAlice変数を定義(sample.d.ts)

 any型は、TypeScriptからはどのような型か分からないJavaScriptのobjectのようなものを表す。つまり厳密な型付けは行えず、型のチェックなどができない代わりに、「何らかのオブジェクト」としては認識して扱えるようになる。

 先ほど行を追加した型定義ファイルを、TypeScriptコードから参照してAliceを利用しようとしてもエラーとならない(図12)。

図12 Aliceがany型として認識されている(app.ts)
図12 Aliceがany型として認識されている(app.ts)

 取りあえずであっても、any型で公開することでコンパイルでき、全く動かず利用できない状態よりはモチベーションを保つことができるので、型定義ファイルを作成する「はじめの一歩」としてはお勧めである。

クラス定義を追加する

 次に、クラスの定義を追加する。今回はJavaScriptライブラリ側にPersonクラスが存在しているので、そのクラスの定義をTypeScript追加する。

 今回追加するクラスの定義は以下のようになる。

TypeScript
……省略……

declare class Person {
  constructor(name: string);
  name: string;
  say(message: string): void;
}
リスト6 クラスの定義を追加(sample.d.ts)

 簡単に説明すると、Personクラスには名前を受け取るコンストラクター(constructor)、名前を持つnameプロパティ、文を受け取るsayメソッドが存在しているため、それぞれnameプロパティやsayメソッドの引数に型の指定(ここでは全て文字列なのでstring)を追加している。

 ここまででapp.tsファイルに戻ると、Personクラスを利用できるようになっているのが確認できる。newにより文字列をコンストラクター引数にしてPersonクラスのインスタンスを作成すると、Visual Studioなら、そこで表示されるIntelliSense(=入力候補)によってsayメソッドなどが存在していることが分かるだろう(図13)。

図13 Personクラスが認識されてnewできるようになる
図13 Personクラスが認識されてnewできるようになる

変数の型をanyからクラスに変更する

 最後に、Aliceの型をanyからPersonに変更して完成となる。以下が型定義ファイル「sample.d.ts」の全コード内容となる。

TypeScript
declare var Alice: Person;

declare class Person {
  constructor(name: string);
  name: string;
  say(message: string): void;
}
リスト8 型定義ファイル(sample.d.ts)の全コード内容

 これでAliceを呼び出したときにも正しく型がPersonクラスとなっていることが認識される(図14)。

図14 Aliceが「Personクラスである」と認識され、sayメソッドを呼び出せる
図14 Aliceが「Personクラスである」と認識され、sayメソッドを呼び出せる

オブジェクトの定義

 ここまではnewできるクラスが定義されているケースの例で説明したが、JavaScriptライブラリの中にはnewできないものもある。例えばjQueryなどは$という変数が定義されているだけで、jQueryクラスが表に出てきているわけではない。そういったものを定義する場合には、インターフェースを利用できる。

 例えば次のようなオブジェクトがJavaScriptのライブラリで定義されている場合で考えてみよう。

JavaScript
var HotCocoa = {
  name: 'ココア',
  price: 400
};
var KilimanjaroCoffee = {
  name: 'キリマンジャロコーヒー',
  price: 600
};
リスト9 共通のメンバーを持つオブジェクトのJavaScriptコード例(Coffee.js)

 これらのHotCocoa/KilimanjaroCoffeeオブジェクトはグローバルに定義され、nameプロパティとpriceプロパティを共通で持っている。

 このような場合には、インターフェースを利用することで解決できる。インターフェースは、実体を持たないインターフェースのみを定義するための記法であり、型定義ファイルに限らず通常のTypeScriptファイルの中でも利用できる。

 インターフェースを使うと、上記のJavaScriptコードに対する型定義は以下のように書くことができる。この例ではHotCocoaKilimanjaroCoffeeの共通のメンバーをインターフェースIDrinkStaticとして定義している。

TypeScript
interface IDrinkStatic {
  name: string;
  price: number;
}
declare var HotCocoa: IDrinkStatic;
declare var KilimanjaroCoffee: IDrinkStatic;
リスト10 オブジェクトに共通するメンバーをインターフェースにまとめた型定義のTypeScriptコード例(Coffee.d.ts)

 インターフェースはもともと実体を持たないため、先ほどのclassキーワードで型定義したものとほぼ同じ記述形式となる。違いはclassinterfaceになり、declareが不要になったところぐらいだ。型定義ファイルのinterfaceの場合は、型定義ファイルを作成する開発者が自由な名前を付けることができるが、他のライブラリや型定義ファイルとの干渉に関しては注意した方がよい。なお、インターフェースの名前は慣習的に「I」で始まるものが多い。

 次の画面は、HotCocoaオブジェクトをTypeScriptコードで記述しているところだ。IDrinkStatic型として認識されていることが分かる。

図15 オブジェクトに関しても型が認識され補完が表示される
図15 オブジェクトに関しても型が認識され補完が表示される

型定義ファイルを作成するコツ

 型定義ファイルを作成する場合には、何事も最初はanyから始めるというのをお勧めしたい。型定義ファイルを作るのは、それなりに時間がかかる作業であるので(例えばjQueryのような巨大ライブラリの型定義ファイルを、もし作ろうと思っても1日やそこらでは作れない)、まずはanyを使って作れるところからというのを心がけるとくじけにくい。

 そもそもはライブラリを使いたいというのが目的であるので、まずはコンパイルできて、本来のコードを書けるようになるというのが肝心である。

 そして少しずつ型定義ファイルを完成に近付け、一通り完成して公開できるものであれば、DefinitelyTypedにPull Requestを投げると、コミュニティへの貢献にもなってよいだろう。

まとめ

 今回はVisual Studioを使って外部ライブラリを利用する方法について触れた。TypeScriptを利用する場合でも自分の書いたコードのみで完結するケースというのは少なく、現実的にはほぼ必ず外部ライブラリは必要となる。

 外部ライブラリを利用する場合には型定義ファイルが必要であり、あればコンパイルできるようになるだけでなくIDEなどのサポートも強化されるのでぜひ活用したい。

 まだ存在していない型定義ファイルも多くあるため、積極的に作成しDefinitelyTypedに貢献してはいかがだろうか? TypeScriptコミュニティを育てる1人になれる良いチャンスだと思うので、ぜひお勧めしたい。

連載:Visual StudioユーザーのためのTypeScript入門(2)
1. TypeScriptとは? Visual Studioを使って開発してみよう

1.0正式版がリリース。TypeScriptは、Visual Studio上でも開発できる。C#などでコードを書いているVisual Studioユーザー向けに、その利用手順や特徴を解説。

連載:Visual StudioユーザーのためのTypeScript入門(2)
2. 【現在、表示中】≫ Visual StudioとTypeScriptでJavaScriptライブラリを活用する

TypeScriptでは大半のJavaScriptライブラリをすぐにそのまま活用できる。Visual Studioで手軽に使う方法や、独自のJavaScriptライブラリを使えるようにする方法を説明する。

サイトからのお知らせ

Twitterでつぶやこう!