TypeScript中的匿名/内联接口实现 [英] Anonymous/inline interface implementation in TypeScript

查看:166
本文介绍了TypeScript中的匿名/内联接口实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've just started with TypeScript and I'm trying to understand why the following inline object definition isn't considered valid. I have a collection of objects - their type is irrelevant (to me), but they implement the interface so that when I iterate through them I know that the interface methods will be present in each object in the collection.

当我尝试创建具有实现所需方法所需的私有信息的对象时,遇到了编译器"错误:

I came across a "compiler" error when I tried to create an object with private information required to implement the required method:

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中不存在" .请注意,如果我在函数调用之外定义对象,即会给出相同的消息,即

The compiler error message is "Argument of type '{ message: string, do: () => void; }' is not assignable to type Doable. Object literal must specify known properties, and 'message' does not exist in type Doable". Note that the same message is given if I define the object outside of the function call, i.e.

var thing: Doable;
thing = {
    private message: 'ahoy-hoy!', // error here
    do: () => {
        alert(this.message);
    }
};
doThatThing(thing);

如果我也添加意外"方法,则会发生相同的错误:

The same error occurs if I add "unexpected" methods as well:

doThatThing({
    do: () => {
        alert("ahoy hoy");
    },
    doSecretly: () => { // compiler error here now
        alert("hi there");
    }
});

我查看了JavaScript,发现内联对象定义中的this的作用域是全局对象:

I looked at the JavaScript and discovered that this within the inline object definition was being scoped to the global object:

var _this = this; // wait, no, why!?
function doThatThing(doableThing) {
    doableThing.do();
}
doThatThing({
    message: 'ahoy-hoy!',
    do: function () {
        alert(_this.message); // uses global 
    }
});

我尝试在TypeScript中搜索有关接口的内联实现的信息,但找不到与该问题有关的任何信息.

I tried searching for information on inline implementations of interfaces in TypeScript, but couldn't find anything speaking to this issue specifically.

我可以确认固定"编译后的JS是否可以按预期工作:

I can confirm that the "fixed" compiled JS works as intended:

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

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

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

...and that makes sense to me, because (as far as I understand) this is implicitly calling the Object constructor, so this should be scoped to the new Object instance.

似乎唯一的解决方案是将每个实现声明为实现该接口的类,但这感觉确实是递归的/繁琐的,因为我将每个类仅具有一个实例.如果唯一带有被调用函数的协定是实现接口,那么为什么对象不能包含其他成员?

It seems like the only solution is to declare each implementation as a class implementing the interface, but that feels really regressive/heavy-handed since I'm only going to have one instance of each class. If the only contract with the called function is implementing the interface, then why can't the object contain additional members?

对不起,结果竟然比我预期的要长...总之,我在问:

Sorry, this turned out longer than I intended ...in summary, I'm asking:

  1. 为什么是内联接口实现(匿名类",正如
  2. 假设这是我的错误(例如,为了防止某些不希望的情况而必须使用编译器错误),是真的这样的唯一解决方案吗?
  1. Why is that inline interface implementation ("anonymous class", as would be said in Java) considered invalid in TypeScript? Specifically, what does that compiler error mean, and what does it protect against?
  2. Why is the scope-reassignment to the global object generated in the "compiled" JavaScript?
  3. Assuming it's my error (e.g. that the compiler error is necessary for protecting against some undesirable condition), is the only solution really to explicitly declare a class in advance, like so?

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中都出现了错误的作用域错误.

P.S. The compiler error only appeared when I upgraded to TS 1.6 today, although the faulty scope bug in the compiled JS occurs in both 1.6 and 1.5.

更新:FrançoisCardinaux提供了指向

Update: François Cardinaux provided a link to this answer, which recommends using a type assertion, but this only removes the compiler error and actually causes a logic error due to improper scope:

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,这是不正确的:

Looking at the compiled JS, this is incorrect:

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的问题-我在这里使用粗箭头=>声明对象的方法:

OK, I finally discovered the problem to question 2 - I was using the fat arrow => to declare the object's method here:

doThatThing(<Doable>{ 
    private message: 'ahoy-hoy!', 
    do: () => { // using fat arrow: global scope replaces new object's scope
        alert(this.message);
    }
});

...将全局范围吸"到该方法中.使用更长的语法可以解决此问题,例如:

...which "sucked" the global scope into the method. The problem is fixed using the longer syntax, like so:

doThatThing(<Doable>{
    private message: 'ahoy-hoy!',
    do: function() { // using "regular" anonymous function syntax, "this" meaning is preserved
        alert(this.message);
    }
});

总而言之:

  1. 未回答;
  2. 我的代码中有一个错字,我应该一直使用"function()"而不是"=>";并且,
  3. 使用接口对对象进行类型声明可消除编译器错误.

这篇关于TypeScript中的匿名/内联接口实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆