打字机:打字机打字从不,但不应该

时间:2017-12-15 23:43:22

标签: typescript

这个问题非常简单,与类型守卫相关:

abstract class A {

    abstract isB(): this is B;
    abstract isC(): this is C;
    abstract get(): number;
}

class B extends A {

    isB(): this is B {
        return true;
    }

    isC(): this is C {
        return false;
    }

    get() {
        return 5;
    }
}

class C extends A {

    isB(): this is B {
        return false;
    }

    isC(): this is C {
        return true;
    }

    get() {
        return 6;
    }
}

const x = new C();
if (x.isB()) {
    console.log("B!")
} else {
    console.log(x.get()); <--- x is inferred to never
}

正如您所看到的,在倒数第二行,x被推断为never,而C非常明显A。我非常确定this issue我已经击中了,我甚至认为了解问题是什么&#34;因为Single可以分配给Empty,代码流分析正在消除联合类型&#34;。

但是,我不了解如何利用建议的解决方法。

如果我没有B作为基类,我确实检查过该问题,而是单独定义Ctype A = B | C,然后说{{ 1}}。在这种情况下,打字稿甚至会在C块中推断出else的类型。我想用继承实现这么好的类型推理是不可能的,我现在设置的方式是什么?

1 个答案:

答案 0 :(得分:6)

你对这个问题是正确的;您的Cx在结构上完全相同,因此TypeScript(包括v2.6)决定如果您已消除Bx的可能性,则您还消除了C B的可能性。这是结构型系统的特征之一;如果您希望编译器区分两种类型,它们应该是可区分的结构(具有一些不同的成员),而不仅仅是名义上(具有不同的名称)。

解决此问题的最简单方法是在CB或两者的定义中添加一些区别属性。它甚至不必在运行时存在;它必须说服编译器Cclass B extends A { readonly className: "B" // add this line // ... no change } class C extends A { readonly className: "C" // add this line // ... no change } 不同。这是一种可能性:

B

现在CclassName具有不同字符串文字类型的const x = new C(); if (x.isB()) { console.log("B!") } else { console.log(x.get()); //<--- x is C } 属性。 (仅在编译时;没有任何额外的内容发送到JavaScript)。确认问题消失了:

std::move

所以,你可以这样做。现在,在2017年12月15日尚未发布的TypeScript v2.7中,将有一个change阻止编译器折叠结构相同但名义上不同的类型情况。我不确定你的上述代码是否会在没有额外属性的情况下突然开始工作,但这是可能的。所以我很快就回来看看。

希望有所帮助。祝你好运!