typescriptはクラスをインターフェイスとして使えるらしい
はじめに
あるオブジェクトに機能を追加したい場合に、委譲するコードを書くことがある。
それそのものとしてのインターフェイスが欲しい場合にはクラスをインターフェイスとして使える
例えば以下の様なオブジェクトがあるとする。
class Container {
constructor(public value: number) {}
display() {
return `node: ${this.value}`;
}
}
console.log(new Container(10).display());
// "node: 10"
この Container
オブジェクトに対して何らかの機能を追加したオブジェクトを作りたい。継承ではなく委譲を使った場合のコードについて考えてみる。
まじめにインターフェイスを定義する
通常は以下の様にインターフェイスを書く(implements
を明示的に指定する必要はないかもしれない)
interface IContainer {
value: number;
display(): string;
}
class PositiveContainer implements IContainer {
constructor(public c: Container) {}
get value(): number {
return this.c.value;
}
set value(value: number) {
if (value < 0) {
throw new Error(`${value} is not positive.`);
}
this.c.value = value;
}
display() {
return this.c.display();
}
}
明示的にimplementsをしたい理由として、委譲元のオブジェクトに機能が追加された時にコンパイルの時点でそれをみつけて欲しいというのがある。
まじめにインターフェイスを定義した場合には、元のオブジェクトと定義したインターフェイスの同期がとれていないとコンパイルエラーにはならない。
クラスをインターフェイスとして使う
implements
の後にクラスを指定した場合に、指定したクラスがインターフェイスとして扱われる。
デコレーター的なオブジェクトを作ろうとした時には便利なような気がしている。
(もっとも、元のオブジェクトと異なるインターフェイスを定義したいという場合もあるのでそのような場合は真面目にインターフェイスを定義するべき)
// IContainerを定義せずに`implements Container` と書いている
class PositiveContainer2 implements Container {
constructor(public c: Container) {}
get value(): number {
return this.c.value;
}
set value(value: number) {
if (value < 0) {
throw new Error(`${value} is not positive.`);
}
this.c.value = value;
}
display() {
return this.c.display();
}
}
参考
typescriptのhandbookにクラスをインターフェイスとして使う例としてmixinを行う例があった
Wrote by PileMd