Typescript标记联合在switch语句中未进行类型检查

3
我正在使用Typescript 3.0.1。在下面的代码中,为什么第7行没有编译器错误?我之前也有这种行为;这是否已从Typescript中删除或存在某种奇怪的回归?
type A = {type :"a"}
type B = {type :"b"}
type Any = A | B

function get<T extends Any>(x: T["type"]): T|undefined {
    switch (x) {
        case "x": return undefined
        default: return undefined
    }
}

看起来像是一个 bug,我创建了这个问题。 - artem
感谢@artem提交此问题,我会跟进处理。 - prmph
1个回答

1
问题归结于checkercheckSwitchStatement中的此代码,该代码自2016年以来一直存在:
                let caseType = checkExpression(clause.expression);
                const caseIsLiteral = isLiteralType(caseType);
                let comparedExpressionType = expressionType;
                if (!caseIsLiteral || !expressionIsLiteral) {
                    caseType = caseIsLiteral ? getBaseTypeOfLiteralType(caseType) : caseType;
                    comparedExpressionType = getBaseTypeOfLiteralType(expressionType);
                }
                if (!isTypeEqualityComparableTo(comparedExpressionType, caseType)) {
                    // expressionType is not comparable to caseType, try the reversed check and report errors if it fails
                    checkTypeComparableTo(caseType, comparedExpressionType, clause.expression, /*headMessage*/ undefined);
                }

(有类似的代码会影响直接比较 x === "x"。) < p > a === b 的规则和类似的 switch 语句是基于双向类型“可比性”的概念,它(省略了很多在这里不相关的细节)表示一个联合成员的一侧必须可分配给另一侧的联合成员。这应该是两侧类型是否重叠的启发式方法。启发式方法对对象的使用方式有效,但对原始值的使用方式效果不佳,在这种情况下,如果 a 的类型是由 string 约束的某个类型参数 T,我们希望能够将其与 "x" 进行比较;既不知道 T 也不知道 "x" 是否可分配给另一个,但 T 可能包含 "x"。因此,当比较的一侧是文字的联合时,而另一侧不是时,代码将文字的联合替换为底层的原始类型。在您的代码中触发了这种情况,其中 "x" 是一个文字,而 T["type"] 不是文字本身,尽管它受到文字的限制。

我认为我们应该提出一个问题,建议您的代码应该给出编译错误。在我写完这句话之后,我看到Artem提出了一个问题,所以我会在那里添加我的分析。

关于您认为之前得到了一个错误的观点,也许您是在考虑以下代码。类型参数上的属性访问的类型将根据类型参数的约束进行尽早解析,因此 y.type 被视为具有类型 "a" | "b",比较的两侧都是文字类型的并集,因此不适用特殊情况。

type A = {type :"a"}
type B = {type :"b"}
type Any = A | B

function get<T extends Any>(y: T): T | undefined {
    switch (y.type) {
        case "x": return undefined
        default: return undefined
    }
}

1
是的,@McCutchen,我相信你的例子就是我之前看到的。我经常惊讶于Typescript推断失败所需的很少的条件。我们将看到这个问题会带来什么结果。 - prmph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接