TypeScript Handbook の「インターフェイスとしてのクラスの使用」セクションには、クラスを拡張するインターフェイスの例があります。
class Point { ... } interface Point3d extends Point {...}
これはいつ役に立ちますか?これの実用的な例はありますか?
このクラスを例にとります:
class MyClass {
public num: number;
public str: string;
public constructor(num: number, str: string) {
this.num = num;
this.str = str;
}
public fn(arr: any[]): boolean {
// do something
}
}
次のようにインスタンスを作成できます。
let a1 = new MyClass(4, "hey");
ただし、次のように、まったく同じインターフェースを満たすオブジェクトを作成することもできます。
let a2 = {
num: 3,
str: "hey",
fn: function(arr: any[]): boolean {
// do something
}
}
a1
はinstanceof
MyClass
ですが、a2
は単なるオブジェクトですが、どちらも同じインターフェースを実装しています。
クラスを拡張するインターフェースのポイントはまさにそれであり、クラスが定義するインターフェースを取得して拡張することができます。
多分それは言語の性質による単なる可能性かもしれませんが、これはそれが役に立つかもしれない場所の例です:
class Map<T> {
private _items: { [key: string]: T };
set(key: string, value: T) { ... }
has(key: string): boolean { ... }
get(key: string): T { ... }
remove(key: string): T { ... }
}
interface NumberMap extends Map<number> {}
interface StringMap extends Map<string> {}
interface BooleanMap extends Map<boolean> {}
function stringsHandler(map: StringMap) { ... }
TypeScriptハンドブックのインターフェイスセクション で説明されています。
インターフェースは、基本クラスのプライベートおよび保護されたメンバーも継承します。つまり、拡張インターフェイスプライベートまたは保護されたメンバーを持つクラス、を作成すると、そのインターフェイスタイプは、そのクラスまたはそのサブクラスによってのみ実装できます。
このような制限は、プライベートおよび保護されたメンバーの継承の副作用のようです。
class Parent
{
private m_privateParent;
}
interface ISomething extends Parent
{
doSomething(): void;
}
class NoonesChild implements ISomething
{
/**
* You will get error here
* Class 'NoonesChild' incorrectly implements interface 'ISomething'.
* Property 'm_privateParent' is missing in type 'NoonesChild'
*/
doSomething()
{
//do something
}
}
class NoonesSecondChild implements ISomething
{
/**
* Nope, this won't help
* Class 'NoonesSecondChild' incorrectly implements interface 'ISomething'.
* Types have separate declarations of a private property 'm_privateParent'.
*/
private m_privateParent;
doSomething()
{
//do something
}
}
class ParentsChild extends Parent implements ISomething
{
/**
* This works fine
*/
doSomething()
{
//Do something
}
}
以下の例を参照してください。
// This class is a set of premium features for cars.
class PremiumFeatureSet {
private cruiseControl: boolean;
}
// Only through this interface, cars can use premium features.
// This can be 'licensed' by car manufacturers to use premium features !!
interface IAccessPremiumFeatures extends PremiumFeatureSet {
enablePremiumFeatures(): void
}
// MyFirstCar cannot implement interface to access premium features.
// Because I had no money to extend MyFirstCar to have PremiumFeatureSet.
// Without feature, what's the use of a way to access them?
// So This won't work.
class MyFirstCar implements IAccessPremiumFeatures {
enablePremiumFeatures() {
}
}
// Later I bought a LuxuryCar with (extending) PremiumFeatureSet.
// So I can access features with implementing interface.
// Now MyLuxuryCar has premium features first. So it makes sense to have an interface to access them.
// i.e. To implement IAccessPremiumFeatures, we need have PremiumFeatureSet first.
class MyLuxuryCar extends PremiumFeatureSet implements IAccessPremiumFeatures {
enablePremiumFeatures() {
// code to enable features
}
}