В TypeScript интерфейс может расширить класс, для чего?

на Руководство По Машинописи в разделе "использование класса в качестве интерфейса" приведен пример интерфейса, который расширяет класс.

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

когда это может быть полезно? У вас есть практические примеры?

3 ответов


Я только что узнал об этой функции, но один из способов, которым это было бы полезно, заключается в том, что вы можете запрограммировать интерфейс без необходимости писать отдельный явный интерфейс.

учитывая класс:

class MyClass {
   public get Something(): number { return this.mSomething; }

   constructor(
      private mSomething: number
   ) {
   }

   public DoSomething() {
      // whatever
   }
}

определите свой интерфейс автоматически. Это также дает вам только одно изменение, так как изменение вашего класса автоматически изменит ваш интерфейс:

interface IMyClass extends MyClass { }

Теперь вы можете использовать интерфейс вместо класса, что делает ваш код намного больше широко применимо:

// forces clients to use your class
public SomeFunctionSomewhereElse(something: MyClass) {
}

// now the client can use your class, or any other class with the same interface
// even ones that haven't been written yet
public SomeFunctionSomewhereElse2(something: IMyClass) {
}

Я думаю, что это не так полезно, как это может быть на некоторых других языках, хотя, поскольку в TypeScript, вы можете просто привести к любому типу, который вы хотите в любом случае.


возьмите этот класс, например:

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

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