我遇到了这个有趣的编译错误,在我看来,Typescript对于自己的好处太聪明了。
private _currentToken: string;
....
private ParseKeyValuePair(): KeyValuePair<string, any>
{
let key = this.RemoveBracketAndQuote(this._currentToken);
this.NextToken();
if (this._currentToken != "=")
throw "Expect = sign but got " + this._currentToken;
this.NextToken();
let val: any = this.RemoveBracketAndQuote(this._currentToken);
if (this._currentToken == "{") //Compile error on this line
val = this.ParseObject();
return new KeyValuePair(key, val);
}
这是我编写的一个快速而又脏的解析器,当使用TS 1.7编译时它可以很好地工作。
将TS升级到2.6后,我收到此编译错误。
构建:运营商&#39; ==&#39;不能应用于键入&#39;“=”&#39;和&#39;“{”&#39;
对我而言,似乎TS看到第一个if语句并确定this._currentToken
必须是字符串"="
,否则将抛出异常。但实际上this._currentToken
会因this.NextToken()
电话而改变,而且TS没有预料到这一点。
它是一个Typescript编译器错误还是我在这里做了一些愚蠢的事情?
编辑:我能够制作一个最小可重复的例子
class Test
{
private property: string;
private changeProperty(): void
{
this.property = "bar";
}
private TestFunc(): void
{
if (this.property != "foo")
throw "bad";
this.changeProperty();
if (this.property == "bar") //compile error
console.log("good");
}
}
答案 0 :(得分:2)
这是一个打字稿功能,虽然在这种情况下它看起来比它有帮助更疼。 Typescript有一个“类型缩小”的概念,如果你沿着某些代码路径限制变量类型,typescript将使用更窄的类型。所以对于你的代码片段,行:
if (this._currentToken != "=")
throw "Expect = sign but got " + this._currentToken;
表示如果当前标记是值"="
之外的任何内容,则该方法将抛出,代码将不会超过该标记。因此,如果代码HAS超过该代码,则该值必须为"="
。换句话说,该行代码已将您的类型缩小为字符串文字“=”。
然后你就行:
if (this._currentToken == "{") //Compile error on this line
val = this.ParseObject();
由于打字稿认为您的this._currentToken
的值"="
不等于"{"
,因此会产生错误。所以(在打字稿的脑海中),这个if语句总是假的,它想给你省点麻烦。
问题是您调用方法nextToken
,我假设它会改变_.currentToken
值。可悲的是,打字稿并没有意识到这一点。
所以你有几个选择
//@ts-ignore
,以打印打字稿。if ((this._currentToken as string) == "{") ...
无论哪种方式,你都必须手动给打字稿提示它的推理不太正确。
答案 1 :(得分:1)
您可以使用类型保护通知类型系统您正在描述的更改:
class Test
{
property: string;
private changeProperty(): this is this & { property: "bar" }
{
this.property = "bar";
return true;
}
private TestFunc(): void
{
if (this.property != "foo")
throw "bad";
if (this.changeProperty()) {
if (this.property == "bar") // no compile error
console.log("good");
}
}
}
它有点hacky,但它确实有效。