我刚开始使用TypeScript,我试图理解为什么以下内联对象定义不被认为是有效的。我有一个对象集合 - 它们的类型与我无关(但对我来说),但它们实现了接口,因此当我遍历它们时,我知道接口方法将出现在集合中的每个对象中。
当我尝试创建一个包含实现所需方法所需的私有信息的对象时,我遇到了“编译器”错误:
interface Doable {
do();
}
function doThatThing (doableThing: Doable) {
doableThing.do();
}
doThatThing({
private message: 'ahoy-hoy!', // compiler error here
do: () => {
alert(this.message);
}
});
编译器错误消息“类型'{ message: string, do: () => void; }'
的参数不能分配给Doable类型。对象文字必须指定已知属性,并且类型为Doable”中不存在“message”。请注意,如果我在函数调用之外定义对象,即
var thing: Doable;
thing = {
private message: 'ahoy-hoy!', // error here
do: () => {
alert(this.message);
}
};
doThatThing(thing);
如果我添加“意外”方法,也会出现同样的错误:
doThatThing({
do: () => {
alert("ahoy hoy");
},
doSecretly: () => { // compiler error here now
alert("hi there");
}
});
我查看了JavaScript并发现内联对象定义中的this
被限定为全局对象:
var _this = this; // wait, no, why!?
function doThatThing(doableThing) {
doableThing.do();
}
doThatThing({
message: 'ahoy-hoy!',
do: function () {
alert(_this.message); // uses global
}
});
我尝试在TypeScript中搜索有关接口的内联实现的信息,但没有找到任何具体说明此问题的内容。
我可以确认“已修复”的已编译JS按预期工作:
function doThatThing(doableThing) {
doableThing.do();
}
doThatThing({
message: 'ahoy-hoy!',
do: function () {
alert(this.message);
}
});
...这对我来说很有意义,因为(据我所知),这是隐式调用Object构造函数,因此this
应限定为新的Object实例。
似乎唯一的解决方案是将每个实现声明为实现接口的类,但这感觉真的是退步/严重,因为我只会有每个类的一个实例。如果与被调用函数的唯一契约是实现接口,那么为什么该对象不能包含其他成员?
对不起,这比我预想的要长...总结一下,我问:
interface Doable {
do() : void;
}
class DoableThingA implements Doable { // would prefer to avoid this ...
private message: string = 'ahoy-hoy';
do() {
alert(this.message);
}
}
class DoableThingB implements Doable { // ... as well as this, since there will be only one instance of each
do() {
document.getElementById("example").innerHTML = 'whatever';
}
}
function doThatThing (doableThing: Doable) {
doableThing.do();
}
var things: Array<Doable>;
things = new Array<Doable>();
things.push(new DoableThingA());
things.push(new DoableThingB());
for (var i = 0; i < things.length; i++) {
doThatThing(things[i]);
}
P.S。编译器错误仅在我今天升级到TS 1.6时出现,尽管编译的JS中的错误范围错误发生在1.6和1.5中。
更新:FrançoisCardinaux提供了this answer的链接,建议使用类型断言,但是这只会消除编译器错误,并且实际上由于范围不正确而导致逻辑错误
interface Doable {
do();
}
function doThatThing (doableThing: Doable) {
doableThing.do();
}
doThatThing(<Doable>{ // assert that this object is a Doable
private message: 'ahoy-hoy!', // no more compiler error here
do: () => {
alert(this.message);
}
});
查看已编译的JS,这是不正确的:
var _this = this; // very wrong, and now hidden
function doThatThing(doableThing) {
doableThing.do();
}
doThatThing({
message: 'ahoy-hoy!',
do: function () {
alert(_this.message); // s/b "this.message", which works in JS (try it)
}
});
答案 0 :(得分:15)
好的,我终于发现了问题2的问题 - 我正在使用胖箭=>
来声明对象的方法:
doThatThing(<Doable>{
private message: 'ahoy-hoy!',
do: () => { // using fat arrow: global scope replaces new object's scope
alert(this.message);
}
});
......将全局范围“吸”到方法中。使用较长的语法修复了该问题,如下所示:
doThatThing(<Doable>{
private message: 'ahoy-hoy!',
do: function() { // using "regular" anonymous function syntax, "this" meaning is preserved
alert(this.message);
}
});
总结如下: