理解打字稿中的构造函数接口

时间:2016-05-18 07:09:25

标签: javascript interface typescript

我是打字稿的新手,我不了解构造函数接口以及它们的类型检查方式。以下是docs的摘录:

interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
    tick();
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("beep beep");
    }
}
class AnalogClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("tick tock");
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);

以下是关于上述代码的文档:

  

因为createClock的第一个参数是ClockConstructor类型,所以   createClock(AnalogClock,7,32),它检查AnalogClock有   正确的构造函数签名。

现在这实际上意味着DigitalClock类或AnalogClock类具有ClockConstructor接口定义的类型。怎么样?它是一个类,接口描述了一个构造函数。

欢迎任何参与者?

1 个答案:

答案 0 :(得分:2)

让我们从您的示例中的简单界面开始:

interface ClockInterface {
    tick();
}

此接口定义此类型的实例包含tick方法,这两个实现此接口:

class MyClock implements ClockInterface {
    public tick(): void {
        console.log("tick");
    }
}

let a: ClockInterface = new MyClock();
let b: ClockInterface = {
    tick: () => console.log("tick")
}

这很简单,因为类实现与其他OO语言相同,第二个实现不是那么简单,但对于javascript开发人员来说应该很容易理解。

这很棒!但是如果我想让一个类的构造函数作为我函数的参数会发生什么呢? 这不起作用:

function constructorClock(ctor: ClockInterface): ClockInterface {
    return new ctor();
}

这里的参数是ClockInterface的实例而不是类(/构造函数),所以为了处理这样的场景,我们可以为类本身而不是实例定义一个接口:

interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}

现在我们可以拥有这个功能:

function constructorClock(ctor: ClockConstructor): ClockInterface {
    return new ctor(3, 5);
}

这些构建器接口给我们的另一个问题是能够为静态类成员/方法定义,对此的一个很好的例子是ArrayConstructor(它是lib.d.ts的一部分):

interface ArrayConstructor {
    new (arrayLength?: number): any[];
    new <T>(arrayLength: number): T[];
    new <T>(...items: T[]): T[];
    (arrayLength?: number): any[];
    <T>(arrayLength: number): T[];
    <T>(...items: T[]): T[];
    isArray(arg: any): arg is Array<any>;
    prototype: Array<any>;
}

(定义因使用ES5ES6目标而异,具体取决于ES5目标。

正如您所看到的,界面定义了不同的构造函数签名,prototypeisArray函数,就像您使用它一样:

Array.isArray([1,2])

如果您没有能力为类本身(而不是实例)提供接口,那么您将无法使用此isArray函数,因为这是错误的:

let a = [];
a.isArray(3);

DigitalClockAnalogClock通过ClockInterface方法(即实例具有此方法)实现tick,但他们使用ClockConstructor函数实现constructor接口,该函数与new一起使用,并返回ClockInterface的实例。

希望这有助于澄清它

修改

构造函数当然不返回interface,它返回一个实现此ClockInterface接口的实例。
也许这会让事情变得更容易:

class BaseClock {
    protected hour: number;
    protected minute: number;

    constructor(hour: number, minute: number) {
        this.hour = hour;
        this.minute = minute;
    }

    public tick() {
        console.log(`time is: ${ this.hour }:${ this.minute }`);
    }
}

class DigitalClock extends BaseClock {
    constructor(hour: number, minute: number) {
        super(hour, minute);
    }

    tick() {
        console.log("digitial");
        super.tick();
    }
}

class AnalogClock extends BaseClock {
    constructor(hour: number, minute: number) {
        super(hour, minute);
    }

    tick() {
        console.log("analog");
        super.tick();
    }
}

interface ClockConstructor {
    new (hour: number, minute: number): BaseClock;
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): BaseClock {
    return new ctor(hour, minute);
}

我们现在只使用类,而不是接口,这更有意义吗?

语法:new (hour: number, minute: number): ClockInterface定义了一个构造函数,这个:

function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    return new ctor(hour, minute);
}

createClock(DigitalClock, 12, 17);

就像:

function createDigitalClock(hour: number, minute: number): ClockInterface {
    return new DigitalClock(hour, minute);
}

createDigitalClock(12, 17);

new ctor(hour, minute);(其中ctorClockConstructor)与new DigitalClock(hour, minute)类似(只是更通用)。