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 "";
}
}
但这一直显示“Types Test 和 ICounter 拥有不兼容的签名”,所以我这里漏掉了什么?我以为接口对类和变量应该是一样工作的。
答案#1
ICounter 表示一个具有两个属性的函数——interval 和 reset。
界面中的这一行...
(start: number): string;
...描述了一种调用该函数的方法。在示例中显示为:
c(10)
其他行描述了该函数的属性——interval 和 reset。
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;
}
答案#2
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 浏览器中也受到支持。如果你想使用函数的原型成员(例如 call 和 apply),可以混合原型:
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; }
}
当然,你可以直接向函数的每个实例添加成员,而不是使用原型。
