在TypeScript中的匿名/内联接口实现。
在TypeScript中的匿名/内联接口实现。
我刚开始学习TypeScript,并且正试图理解为什么以下内联对象定义被认为无效。我有一组对象-它们的类型对我来说不重要,但它们实现了接口,以便当我遍历它们时,我知道接口方法将在集合中的每个对象中存在。
当我尝试创建一个具有实现所需方法所需的私有信息的对象时,我遇到了一个“编译器”错误:
接口 Doable {
do();
}
function doThatThing(doableThing: Doable) {
doableThing.do();
}
doThatThing({
private message: 'ahoy-hoy!', // 在这里出现编译器错误
do: () => {
alert(this.message);
}
});
编译器错误消息是“类型“{ message: string, do: () => void; }”的参数不可分配给类型Doable。对象文字必须指定已知属性,并且'message'在类型Doable中不存在”。请注意,如果我在函数调用之外定义对象,即
var thing: Doable;
thing = {
private message: 'ahoy-hoy!', // 在这里出现错误
do: () => {
alert(this.message);
}
};
doThatThing(thing);
如果我还添加了“意外”的方法,也会出现相同的错误:
doThatThing({
do: () => {
alert("ahoy hoy");
},
doSecretly: () => { // 现在在这里出现编译器错误
alert("hi there");
}
});
我查看了JavaScript代码,并发现内联对象定义中的“this”被作用域限定为全局对象:
var _this = this; // 等等,不对,为什么!?
function doThatThing(doableThing) {
doableThing.do();
}
doThatThing({
message: 'ahoy-hoy!',
do: function () {
alert(_this.message); // 使用全局对象
}
});
我尝试搜索有关TypeScript中内联接口实现的信息,但找不到任何与此问题有关的内容。
我可以确认“修复”的编译JS按预期工作:
function doThatThing(doableThing) {
doableThing.do();
}
doThatThing({
message: 'ahoy-hoy!',
do: function () {
alert(this.message);
}
});
这对我来说是有道理的,因为(据我了解)这会隐式调用Object构造函数,因此“this”应该作用域限定为新的Object实例。
似乎唯一的解决方案是将每个实现声明为实现接口的类,但是这感觉非常倒退/过度,因为每个类只会有一个实例。如果与调用函数的唯一合同是实现接口,那么为什么对象不能包含其他成员呢?
抱歉,这个问题比我预想的要长......总结一下,我想问:
1. 为什么TypeScript中的内联接口实现(如在Java中所说的“匿名类”)被认为无效?具体来说,编译器错误意味着什么?它起到了什么保护作用?
2. 为什么在“编译”生成的JavaScript中会生成将作用域重新分配给全局对象的错误?
3. 假设这是我的错误(例如,编译器错误对保护某些不希望发生的情况很重要),那么唯一的解决方案真的是事先显式声明一个类吗?
接口 Doable {
do() : void;
}
class DoableThingA implements Doable { // 不想这样做...
private message: string = 'ahoy-hoy';
do() {
alert(this.message);
}
}
class DoableThingB implements Doable { // ... 还有这个,因为每个只会有一个实例
do() {
document.getElementById("example").innerHTML = 'whatever';
}
}
function doThatThing(doableThing: Doable) {
doableThing.do();
}
var things: Array
things = new Array
things.push(new DoableThingA());
things.push(new DoableThingB());
for (var i = 0; i < things.length; i++) {
doThatThing(things[i]);
}
P.S.编译器错误仅在我今天升级到TS 1.6时出现,尽管在1.6和1.5中都存在编译JS中的错误作用域问题。
更新:François Cardinaux提供了一个链接到这个答案,建议使用类型断言,但这只是消除了编译器错误,并且由于错误的作用域而导致逻辑错误:
interface Doable {
do();
}
function doThatThing(doableThing: Doable) {
doableThing.do();
}
doThatThing(
private message: 'ahoy-hoy!', // 在这里不再有编译器错误
do: () => {
alert(this.message);
}
});
看着编译后的JS,这是不正确的:
var _this = this; // 非常错误,而且现在隐藏起来了
function doThatThing(doableThing) {
doableThing.do();
}
doThatThing({
message: 'ahoy-hoy!',
do: function () {
alert(_this.message); // 应该是"this.message",这在JS中有效(试试看)
}
})。