javascript - TypeScript 中的匿名/内联接口(interface)实现

标签 javascript interface typescript typescript1.6

我刚刚开始使用 TypeScript,我正在尝试理解为什么以下内联对象定义被视为无效。我有一个对象集合 - 它们的类型(对我而言)无关紧要,但它们实现了接口(interface),因此当我遍历它们时,我知道接口(interface)方法将出现在集合中的每个对象中。

当我尝试使用实现所需方法所需的私有(private)信息创建对象时遇到“编译器”错误:

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; }' is not assignable to type Doable. Object literal must specify known属性,并且“消息”在 Doable 类型中不存在”。请注意,如果我在函数调用之外定义对象,则会给出相同的消息,即

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 中接口(interface)的内联实现的信息,但找不到任何专门针对此问题的信息。

我可以确认“固定”编译的 JS 按预期工作:

function doThatThing(doableThing) {
    doableThing.do();
}

doThatThing({
    message: 'ahoy-hoy!',
    do: function () {
        alert(this.message);
    }
});

...这对我来说很有意义,因为(据我所知)这是隐式调用 Object 构造函数,所以 this 的范围应该是新的 Object 实例。

似乎唯一的解决方案是将每个实现声明为一个实现接口(interface)的类,但这感觉真的很倒退/笨手笨脚,因为我每个类只有一个实例。如果与被调用函数的唯一约定是实现接口(interface),那么为什么对象不能包含其他成员?

抱歉,结果比我预期的要长......总而言之,我要问的是:

  1. 为什么内联接口(interface)实现(“匿名类”,如 in Java )在 TypeScript 中被认为是无效的?具体来说,该编译器错误是什么意思,它可以防止什么?
  2. 为什么在“已编译”的 JavaScript 中生成对全局对象的范围重新分配?
  3. 假设这是我的错误(例如,编译器错误对于防止某些不良情况是必要的),是否真的是像这样提前显式声明一个类的唯一解决方案?
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]);
}

附言今天升级到TS 1.6才出现编译错误,虽然1.6和1.5都出现了编译JS的faulty scope bug。

更新:François Cardinaux 提供了指向 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)
    }
});

最佳答案

好的,我终于发现了问题 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);
    }
});

总结一下:

  1. 无人接听;
  2. 我的代码中有一个拼写错误,我应该使用“function()”而不是“=>”;并且,
  3. 使用接口(interface)对对象进行类型断言可消除编译器错误。

关于javascript - TypeScript 中的匿名/内联接口(interface)实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32628864/

相关文章:

javascript - 用拖放替换图像

javascript - 如何使用装饰器扩展类类型

javascript - Typescript实际上在什么阶段进行编译?

javascript - 使用显示 block 单击按钮时不显示 HTML 表格

javascript - MS Edge 不断重新加载的调试 - 如何触发调试器?

c# - ClientBase<TChannel> 和 ChannelFactory<TChannel> 的代码生成?

typescript - 类型 'string' 的索引签名在类型 'Object' .ts(2322) 中丢失

reactjs - 如何使用 react-native-testing-library getByRole

javascript - 文本区域中的输入类型

java - 在 Java 中实现一个接口(interface)并覆盖方法?