TypeScriptの基本
TypeScriptの概要を理解したところで、具体的なコードでもってTypeScriptの威力を確認していきましょう。以下は、
- toStringメソッドを持ったAnimalクラス
- Animalクラスを継承したHamsterクラス(独自のメソッドとしてwalkを公開)
を定義したTypeScriptのコードです。
比較のために、コンパイル済みのJavaScriptのコード(注2)も併記しておきます(内容はコメントでざっと把握できれば十分です)。JavaScriptでは冗長にならざるを得なかったコードが、TypeScriptによってぐんとコンパクトに、しかも、C#、Javaなどに慣れた開発者にとっても直感的に分かりやすいものになったことが確認できるはずです。
Visual StudioでのTypeScriptコードの作成/コンパイル方法については、次節で改めます。
// (1)CodeZineSampleモジュールを定義 module CodeZineSample { // (2)Animalクラスを定義 export class Animal { // (4)コンストラクターでname/ageフィールドを初期化 constructor(public name: string, public age: number) { } // (5)toStringメソッドを定義 public toString(): string { return this.name + ':' + this.age + '歳'; } } // (3)Animalクラスを継承したHamsterクラスを定義 export class Hamster extends Animal { // (6)walkメソッドを定義 public walk(): string { return this.name + 'はトコトコ歩いています。'; } } } // (7)CodeZineSample.Hamsterクラスのメソッドを呼び出し import s = CodeZineSample; var h = new s.Hamster('トクジロウ', 15); console.log(h.toString()); // 結果:トクジロウ:15歳 console.log(h.walk()); // 結果:トクジロウはトコトコ歩いています。 ----------------------------------------------------------------------- // 継承のための関数を準備 var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; // CodeZineSampleモジュールを定義 var CodeZineSample; (function (CodeZineSample) { // Animalクラスを定義 var Animal = (function () { // コンストラクターでname/ageフィールドを初期化 function Animal(name, age) { this.name = name; this.age = age; } // toStringメソッドを定義 Animal.prototype.toString = function () { return this.name + ':' + this.age + '歳'; }; return Animal; })(); CodeZineSample.Animal = Animal; // Animalクラスを継承したHamsterクラスを定義 var Hamster = (function (_super) { __extends(Hamster, _super); // 基底クラスのコンストラクターを呼び出し function Hamster() { _super.apply(this, arguments); } // walkメソッドを定義 Hamster.prototype.walk = function () { return this.name + 'はトコトコ歩いています。'; }; return Hamster; })(Animal); CodeZineSample.Hamster = Hamster; })(CodeZineSample || (CodeZineSample = {})); // CodeZineSample.Hamsterクラスのメソッドを呼び出し var s = CodeZineSample; var h = new s.Hamster('トクジロウ', 15); console.log(h.toString()); console.log(h.walk()); //# sourceMappingURL=myApp.js.map
以降では、コードの詳細を掻い摘んでみていきましょう。
モジュールとクラス
まず、(1)は内部モジュールの定義です(注3)。いわゆるC#の名前空間、Javaのパッケージに相当する要素で、moduleキーワードによって表します。
モジュールの中には、クラス(class)/インターフェイス(interface)/列挙型(enum)など、これまたオブジェクト指向開発にはおなじみの要素を定義できます。例えば(2)ではclassキーワードを利用して、Animalクラスを定義しています。(3)のように、extendsキーワードを利用することで継承を表現することもできます。サーバーサイドの開発者でもごく直感的に理解できる、これらオブジェクト指向構文は、TypeScriptのもっとも重要な機能の一つです。
classキーワードの直前にあるexportキーワード((2))は、モジュールの外からクラスを参照できることを意味します。exportキーワードがない場合、TypeScriptはモジュール配下の要素へのアクセスを許可しませんので、注意してください。
内部モジュールというからには外部モジュールもあるわけですが、こちらはクライアントサイド開発ではあまり利用しませんので、まずはあまり気にしなくて構いません。
コンストラクターとメソッド
Animalクラスの配下では、コンストラクターとtoStringメソッドを定義しています。TypeScriptでは、コンストラクターの名前はconstructorで固定です。
コンストラクターの引数にも注目してください((4))。冒頭で触れたように、TypeScriptでは静的型付けに対応した言語です。「仮引数名: 型名」の形式でデータ型を宣言しておくことで、想定外の型は設定できないようになります。型の指定は任意ですが、TypeScriptを使っているならば、あえて明示しない意味はありません。型名として利用できるのは、string、number、booleanなどのプリミティブ型の他、任意のオブジェクト型です。
引数に付与されたpublicキーワードは、アクセス修飾子です。TypeScriptでは、コンストラクターの引数にpublic/privateなどのアクセス修飾子を付けることで、これを対応するメンバー変数(フィールド)として設定するという決まりがあります。よって、(4)の例であれば、「string型のnameフィールド、number型のageフィールドをpublic権限で定義、引数の値で初期化しなさい」という意味になります。あえて冗長に表すならば、以下のコードとほぼ同意です。
public name : string; public age : number; constructor(name: string, age: number) { this.name = name; this.age = age; }
コンストラクターの主な役割がメンバー変数の初期化であることを考えれば、これだけのコードを省力化できるのはなかなかに嬉しい仕組みですね。
toString((5))、walk((6))メソッドのように一般のメソッドでは、「: string」のように、メソッドシグニチャーの中で戻り値の型を明示的に指定することも可能です。
インポート宣言
モジュール配下のクラスをインスタンス化する場合、「new CodeZineSample.Hamster(……)」のように完全修飾名で表しても構いませんが、モジュールの階層が深くなってくると自ずと名前も長くなり、コードの可読性を損なう恐れがあります。
そこでTypeScriptでは、import命令を利用することで、モジュールに別名を付与できます。この例であれば、CodeZineSampleモジュールに対して「s」という別名を与えています((7))。これによって、「new s.Hamster(……)」のような表記が可能になるわけです。
以上が、TypeScriptの基本的な構文ルールです。もちろん、ここで触れた内容はごく大雑把なものなので、より詳しい文法/構文については、以下のサイトも参照してください。記事末尾では、関連書籍も紹介しています。