我遇到了这个有趣的编译错误,在我看来,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后,我收到了这个编译错误。
构建:运算符'=='不能应用于键入'“=”'和'“{”'
对我来说似乎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");
}
}
这是一个打字稿功能,虽然在这种情况下它看起来比它有帮助更疼。 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) == "{") ...
无论哪种方式,你都必须手动给打字稿提示它的推断不太正确。
您可以使用类型保护来通知类型系统您正在描述的更改:
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,但它的工作原理。