TypeScript 2.0ではプロパティおよびインデックスシグネチャを読み込み専用とするreadonly修飾子が追加されている。
以下に簡単な例を示す。
class Foo {
readonly name: string; = 'no name'
constructor(name: string) {
this.name = name;
}
}
var f = new Foo('insider.net');
f.name = 'buildinsider'; // エラー
readonly修飾子を付加したプロパティの値は初期化子もしくはコンストラクタでセットする。すぐに予想が付くように、変数fのnameプロパティは「readonly」なので、このプロパティへの代入はエラーとなる。なお、クラスFooは次のようによりコンパクトに記述できる。
class Foo {
constructor(public readonly name = 'no name') {
}
}
ただし、readonly修飾子を付加した全てのプロパティが変更不可能となるとは限らないので注意しよう。以下に例を示す。
class Bar {
constructor(public bar: string) {
// Barクラスのbarプロパティはreadonlyではない
}
}
class Baz {
constructor(public readonly bar: Bar) {
// Bazクラスのbarプロパティはreadonly
}
}
var bar = new Bar('bar');
var baz = new Baz(bar);
baz.bar.bar = 'hogehoge'; // 変更可能!
baz.bar = new Bar('new bar'); // これは変更不可能
TypeScript 2.0では抽象クラスのプロパティ、アクセサーにabstract修飾子を付加できるようになった。その派生クラスではそれらを宣言するか、abstract修飾子を再度付加する必要がある。TypeScript 2.0では、抽象プロパティには初期化子を付加することはできず、抽象メソッドはその実装を持つことができない。
以下に例を示す。
abstract class Base {
protected abstract prop: string;
abstract method(): string;
abstract method2: () => string;
}
class Derived extends Base {
constructor(protected prop: string = 'insider.net') {
super();
}
method() { return this.prop; }
method2 = () => `hello ${this.prop}`;
}
const d = new Derived()
console.log(d.method());
console.log(d.method2());
クラスBaseでは3つの抽象プロパティ(メソッド)を宣言している。そして、クラスDerivedではそれらを宣言している。method/method2の2つのメソッドは実質的にはシグネチャを持つものだが、このような宣言の仕方も可能ということで、別々に記述してある。クラスベースのオブジェクト指向プログラミングにおいては、抽象基底クラスでそのクラスに属する(派生)クラスが持つ特性だけを記述しておき、具象派生クラスでそれらの実装を行うことがよくある、TypeScript 2.0でもこれがサポートされるようになったといえる。
また、クラスのプロパティやメソッドをオプションとすることも可能になっている。この機能を使用するには、tsconfig.jsonファイルでコンパイラオプションの「strictNullChecks」をtrueにするか、コマンドラインでのコンパイル時に「--strictNullChecks」を指定する必要がある。
オプションのプロパティ/メソッドはその名前に「?」を付加して表す。以下に例を示す。
class OptProp {
constructor(public name: string, public addr?: string) {
}
goodbye?: (this: OptProp) => void;
hello(): void {
if (typeof this.addr === 'string') {
console.log(`hello ${this.name} on ${this.addr}`);
} else {
console.log(`hello ${this.name}`);
}
}
}
var op = new OptProp('insider.net');
op.hello();
op.goodbye = function(this: OptProp) { console.log(`goodbye ${this.name}`); };
op.goodbye();
ここでは、OptPropクラスを定義して、そのaddrプロパティとgoodbyeメソッドをオプションとしている。これらの型は、型注釈で指定した型かundefinedとなる。つまり、addrプロパティの型は「string | undefined」の共用型に、goodbyeメソッドの型は同様に「(this: OptProp) => void | undefined」の共用型となる。
OptPropクラスのインスタンス生成時にコンストラクタの第2引数として文字列を渡せば、addrプロパティの型はstringとなり、その値がaddrプロパティの値となる。省略すれば、addrプロパティの型はundefinedとなり、値は設定されない。googbyeメソッドは後で設定している(後述)。
OptPropクラスのhelloメソッド内では、addrプロパティの型がstringかundefinedかに応じた処理を行うようにしている(型ガードが効くので、if節内部ではaddrプロパティをstring型にキャストする必要がないことに注意)。
goodbyeメソッドは、クラス定義の外側で「op.goodbye = ……」のようにして設定してやっている。ちなみにgoodbyeメソッドのシグネチャに含まれている「(this: OptProp)」というのは、やはりTypeScript 2.0で導入された関数の暗黙の第1引数となるthisの型を指定するものだ(ここではメソッドを定義しているので、当然のようにthisパラメーターの型にはOptPropクラスを指定している)。これを省略して、次のようにしても恐らくエラーとはならないだろうが、IntelliSenseによる支援は利かなくなるかもしれない(この場合は、関数内にある「this.name」の型がstringであることが分からなくなる)。
class OptProp {
constructor(public name: string, public addr?: string) {
}
goodbye?: () => void;
…… 省略 ……
}
…… 省略 ……
op.goodbye = function() { console.log(`goodbye ${this.name}`); };
クラス定義外部でこのクラスのインスタンスを生成した後に、そのgoodbyeプロパティに「(tis: OptProp) => void」というシグネチャに合った関数をセットしてやり、その関数を呼び出すことで、「goodbye ……」とコンソールに出力されるようになっている。
この他にもprivateコンストラクタ/protectedコンストラクタの追加をはじめとするさまざまな拡張がTypeScript 2.0では行われている。詳細については、リリースノートを参照されたい。本稿の最後にTypeScript 2.1で追加された機能をざっと見ていこう。
Copyright© Digital Advantage Corp. All Rights Reserved.