从混合接口类型创建类

时间:2015-08-14 18:10:16

标签: interface typescript

首先,我对TS非常陌生,在我阅读期间 http://www.typescriptlang.org/Handbook我试图了解混合类型接口的工作原理。

在TS的例子中:

interface ICounter {
    (start: number): string;
    interval: number;
    reset(): void;
}
var c: ICounter;
c(10);
c.reset();
c.interval = 5.0;

所以,问题是当我尝试使用这个接口编写一个类时,问题就在于:

(start: number): string;

首先我认为这一行代表了一个试图创建的函数:

class Test implements ICounter {
    interval: number;

    reset(): void { }

    start(start: number): string {
        return "";
    }
}

但这表明"类型测试和ICounter有不兼容的签名",所以我在这里失踪了什么?我认为接口应该对类和变量的工作方式相同。

2 个答案:

答案 0 :(得分:1)

ICounter表示具有两个属性的函数 - intervalreset

界面中的这一行......

(start: number): string;

...描述了一种调用函数的方法。它在示例中显示为:

c(10)

其他行描述了函数的属性 - intervalreset

c.reset();
c.interval = 5.0;

如手册中所述,这用于表示执行此操作的JavaScript库。例如,上面的代码可能代表以下JavaScript代码:

function counter(start) {
    alert(start);
    return "some string";
}

counter.reset = function() { alert('reset called'); };
counter.interval = 1;

除此之外,请注意您描述的类可以通过以下界面表示:

interface ITest {
    interval: number;
    reset: () => void;
    start: (start: number) => string;
}

答案 1 :(得分:0)

class表示您将通过new运算符创建实例。 new创建object,而不是function,因此无法实现类,哪些实例可以作为函数调用。你可以这样做:

interface ICounterObject {
    interval: number;
    reset(): void;
}

interface ICounter extends ICounterObject {
    (start: number): string;
    __proto__: ICounterObject;
}

class Test implements ICounterObject {
    static createCounter(): ICounter {
        var counter = <ICounter>function (start: number): string {
            return "";
        };
        counter.__proto__ = Test.prototype;
        return counter;
    }

    interval: number;

    reset(): void { }
}

注意,__proto__来自ES6,但ES5浏览器支持事实上的。如果你想使用函数原型成员(例如callapply)混合原型:

function mixWithFunc<T extends Function>(obj: { __proto__?}, func: T) {
    var objProto = <{ constructor }>obj.__proto__;
    var objClass = <{ __mixedProto__ }>objProto.constructor;
    var proto = <typeof obj>objClass.__mixedProto__;
    if (!proto) {
        proto = {};
        proto.__proto__ = objProto;
        ['call', 'apply', 'bind'].forEach(p => proto[p] = Function.prototype[p]);
        objClass.__mixedProto__ = proto;
    }
    (<typeof obj>func).__proto__ = proto;
    Object.getOwnPropertyNames(obj).forEach(p => func[p] = obj[p]);
    return func;
}

interface ICounter extends Counter {
    (start: number): string;
}

class Counter {
    static create() {
        var self: ICounter = mixWithFunc(
            new Counter(),
            <ICounter>function (start: number) {
                return "started with interval: " + self.interval;
            });
        return self;
    }

    interval = 1000;

    reset() { this.interval = 0; }
}

当然,你可以只为你的每个函数实例添加成员而不是原型。