打字稿:操作员' =='不能应用于'" ="'和'" {"'

时间:2017-12-28 00:35:58

标签: typescript typescript2.0

我遇到了这个有趣的编译错误,在我看来,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");
    }
}

2 个答案:

答案 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,但它确实有效。