首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型守卫:打印文本推断永远不会,但不应该

类型守卫:打印文本推断永远不会,但不应该
EN

Stack Overflow用户
提问于 2017-12-15 23:43:22
回答 1查看 499关注 0票数 4

这个问题非常简单,与类型保护有关:

代码语言:javascript
复制
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作为基类,而是独立地定义BC,然后说type A = B | C,我就检查这个问题是否会出现。在这种情况下,类型记录甚至推断出C块中的类型。我想用继承实现这么好的类型推断是不可能的,就像我现在设置它的方式一样?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-12-16 00:59:56

在这个问题上,您是正确的;您的BC在结构上是相同的,因此TypeScript (直到并包括v2.6)决定,如果您消除了xB的可能性,那么您也消除了xC的可能性。这是结构类型系统的特性之一;如果您希望编译器区分两种类型,那么它们在结构上应该是可区分的(有一些不同的成员),而不仅仅是名义上(有不同的名称)。

解决这个问题的最简单方法是在BC的定义中添加一些不同的属性,或者两者兼而有之。它甚至不需要在运行时存在;它只需要让编译器相信BC是不同的。这里有一种可能性:

代码语言:javascript
复制
class B extends A {

    readonly className: "B"  // add this line

    // ... no change

}

class C extends A {

    readonly className: "C"  // add this line

    // ... no change

}

现在,BC具有不同字符串文本类型的className属性。(仅在编译时,不向JavaScript发出任何额外的信号)。确认问题解决了:

代码语言:javascript
复制
const x = new C();
if (x.isB()) {
    console.log("B!")
} else {
    console.log(x.get()); //<--- x is C
}

所以你可以这么做。现在,在截至2017年12月15日尚未发布的TypeScript v2.7中,将有一个变化来防止编译器在某些情况下崩溃--结构相同但名义上不同的类型。我不确定您的上述代码是否会在没有额外属性的情况下突然开始工作,但这是可能的。我想很快就回来看看吧。

希望这能有所帮助。祝好运!

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47841211

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档