TypeScript入門―大規模開発に適したJavaScript互換言語

この記事を読むのに必要な時間:およそ 8.5 分

モジュール

TypeScriptにはモジュールと呼ばれるしくみがあります。モジュールには外部モジュールと内部モジュールがありますが,ここでは内部モジュールを説明します。モジュールとは簡単に言えばクラスを特定のかたまり(モジュール)に分割して管理することを支援するためのしくみです。クラスが多くなる場合や,ライブラリを作るうえでは必須とも言える機能です。リスト4のコードにはGreeterというクラスが2つ出てきますが,これらは異なるクラスです。

リスト4 モジュールの例

module Sample.Module1 {
    export class Greeter {
        hello(): void { alert('Hello!'); }
    }
}
module Sample.Module2 {
    export class Greeter {
        hello(): void { alert('Konnichiwa!'); }
    }
}
new Sample.Module1.Greeter().hello(); // => Hello!
new Sample.Module2.Greeter().hello(); // => Konnichiwa!

モジュールを定義するにはmodule ModuleName {…… }というブロックでモジュールに含めたいコードを囲みます。デフォルトではモジュール内で定義されたクラスはそのモジュールで閉じていて,外部からはアクセスできません。外部からアクセスしようとすると,コンパイルエラーになります。公開して外部からアクセス可能にする場合は,classなどの定義の前にexport修飾子を指定する必要があります。

module Sample.Module3 {
    class Greeter {
        hello(): void { alert('Hi!'); }
    }
}
new Sample.Module3.Greeter().hello();
// => classをexportしていないのでコンパイルエラー

インタフェース

TypeScriptにはインタフェースと呼ばれるしくみがあります。インタフェースは,簡単に言えば「こんなメソッドやプロパティたちを持っている」ことを表す定義です。

たとえば,次のコードはmessageプロパティを持つインタフェースを指定したクラスを定義しています。

interface IGreeting {
    message: string;
}
class Hello implements IGreeting {
    message = 'Hello!';
}
class Konnichiwa implements IGreeting {
    message = 'Konnichiwa!';
}
function say(greeting: IGreeting): void {
    alert(greeting.message);
}

say(new Hello()); // => Hello!
say(new Konnichiwa()); // => Konnichiwa!

インタフェースはクラスの宣言の一部として指定でき,特定のメソッドやプロパティを持つことを強制できます。このコードのclass Hello implements IGreetingという宣言は,⁠クラスHelloIGreetingインタフェースのメソッドを持つ必要がある」ということを意味します。実際,Helloクラスからmessageプロパティを削除するとコンパイルエラーになります。

代入の互換性

TypeScriptのインタフェースやクラスは,プロパティの型やメソッドのシグネチャが同じか要求に足りているなどの互換性があれば,明示的に型を宣言していなくても代入可能です。これは少し特徴的な点です。たとえばリスト5のコードはTypeScriptとして問題なくコンパイルできて実行できます。

リスト5 代入に互換性がある例

interface IGreeting {
    message: string;
}
function say(greeting: IGreeting): void {
    alert(greeting.message);
}
// IGreetingと同じプロパティを持つがIGreetingの実装を明示的に宣言していない
class Hi {
    message = 'Hi!';
}
// HiクラスはIGreetingとして扱える
say(new Hi()); // => Hi!
// 匿名オブジェクトはstring型のmessageプロパティがあるのでIGreetingとして扱える
say({ message: 'Ohayo-gojyaimasu!' }); // => Ohayo-gojyaimasu!

一方,次のコードのように互換性がない場合はコンパイル時にエラーとなります。1行目は匿名オブジェクトのmessageプロパティの型がstringではないのでエラーになり,2行目は匿名オブジェクトにmessageプロパティがないのでエラーになります。

say({ message: 1 });
say({ msg: 'Hoge!' });

その他の機能

TypeScriptには,ここまでに紹介した特徴以外にもさまざまな機能があります。

  • ジェネリクス
  • プロパティ(getter/setter)
  • 列挙型(Enum)
  • インデクサ
  • import対応

機能は多いですが,そのぶん使いこなせるととても強力で,開発効率を高めるツールとなるでしょう。

外部ライブラリと定義

ここまでTypeScript自体の紹介をしてきましたが,最後に実際にアプリケーションを開発するときには必ずと言ってよいほど必要になるライブラリとその使い方を紹介します。

TypeScriptを利用した開発で使うライブラリは,ほとんどの場合JavaScriptで書かれたものです。たとえばブラウザであればjQueryやKnockout.js,AngularJS注2など,Node.jsであればSocket.ioやexpressなどです。これらのライブラリはJavaScriptで書かれているため,TypeScriptの最大の特徴である厳密な型を持っていないという問題があります。

そこでTypeScriptには,ソースコードとは別に型定義のみを記述して参照するしくみが用意されてます。型定義ファイルは.d.tsという拡張子を持ち,TypeScriptのソースコードからは特殊なコメントを書くことで参照できます。型定義ファイルを参照すれば,JavaScriptのライブラリも型が定義されているように扱えます。つまり,IDEのサポートを受けたりコンパイル時のチェックを受けたりできるので,TypeScriptで書かれたコードの延長のように扱えるのです図6)⁠

図6 Visual Studio上でjQueryの補完ができる

図6 Visual Studio上でjQueryの補完ができる

しかし,開発者がいちいち型定義ファイルを作成するのは現実的ではありません。有名なライブラリの型定義ファイルを集約しているDefinitelyTypedというコミュニティプロジェクトがGitHubにあり,jQueryやKnockout.jsといった数多くのライブラリの型定義ファイルが集められています注3)⁠VisualStudioであればNuGetから,Node.jsであればnpmパッケージからtsdコマンドをインストールすれば簡単に取得/利用できます。

注2)
発売中のWEB+DB PRESS Plusシリーズフロントエンド開発徹底攻略のP.171で詳しく解説しています。参考にしてください。
注3)
2014年6月時点では450を超えるライブラリの型定義がある。

まとめ

ほんの触り程度の紹介しかできませんでしたが,TypeScriptは奥が深く,非常に実用的な言語です。静的型付け言語である点と開発コミュニティが活発な点でとても強力な言語だと思いますので,規模が大きい,または大きくなる可能性があるアプリケーションや,保守が続くアプリケーションの開発にぜひ採用してみてはいかがでしょうか。

提供/株式会社グラニ
http://grani.jp/
グラニでは各種エンジニアを募集しています。
詳細はこちら→http://grani.jp/recruit/

著者プロフィール

沢渡真雪(さわたりまゆき)

普段はASP.NETやPerlでWebアプリケーションを書くのが主。興味の向きはWindows一般から.NET Framework,Perl(Plaggerとか)やMac OS Xなど。

URLhttp://www.misuzilla.org/