web-dev-qa-db-ja.com

TypeScriptでは、インターフェイスはクラスを拡張できますが、何のためですか?

TypeScript Handbook の「インターフェイスとしてのクラスの使用」セクションには、クラスを拡張するインターフェイスの例があります。

class Point { ... } interface Point3d extends Point {...}

これはいつ役に立ちますか?これの実用的な例はありますか?

19
zuraff

このクラスを例にとります:

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
    }
}

a1instanceofMyClassですが、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) { ... }
9
Nitzan Tomer

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
    }
}
7
antonpv
  • インターフェイスの使用を制限します。
  • どのクラスもインターフェースを実装したくない場合は、このソリューションを使用できます。
  • インターフェイス 'I'がクラス 'C'を拡張するとします。次に、「I」は「C」またはその子によってのみ実装できます。
  • または、クラスが「I」を実装する必要がある場合は、最初に「C」を拡張する必要があります。

以下の例を参照してください。

// 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
    }
}
2
Jose