在TypeScript中的匿名/内联接口实现。

14 浏览
0 Comments

在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({ // 断言这个对象是一个Doable

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中有效(试试看)

}

})。

0