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

标签 javascript typescript types switch-statement discriminated-union

我使用的是 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
    }
}

最佳答案

问题归结为 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"。)

a === b 和类似的 switch 语句的规则基于双向类型“可比性”的概念,其中(省略了很多与此处无关的细节)表示一侧的联合成分必须可分配给另一侧的联合成分。这应该是对两侧类型是否重叠的启发式。启发式方法适用于对象通常使用的方式,但不适用于原语,其中(例如)如果 a 的类型是某种类型参数 Tstring,我们希望能够将它与"x"进行比较; T"x" 都不知道可以分配给另一个,但是 T 可能包含 "x" .因此,当比较的一侧是文字并集而另一侧不是时,代码会将作为文字并集的一侧替换为基础原始类型。这种情况在您的代码中触发,其中 "x" 是文字,而 T["type"] 本身不是文字,尽管它是 constrained 通过文字的联合。

我认为我们应该提出一个问题,建议您的代码应该给出一个编译错误。在我写完那句话之后,我看到 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
    }
}

关于javascript - typescript 标记联合未在 switch 语句中进行类型检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52087511/

相关文章:

javascript - ReactJS中ClassicComponentClass和ComponentClass的区别

typescript - 选取除指定属性之外的所有属性

java - Java的原始类型是什么?

object - 返回 interface{} 而不是 int64 时的额外分配

javascript - 为什么协变/逆变意味着只读/只写?

node.js - EXPORT 在部署在 pm2 中的 ts 文件 Node 应用程序中不起作用

javascript - 无法在 AngularJS 的数组中添加或删除元素

javascript - Sencha 触摸 2 : Passing data from controller to a view

javascript - 验证电子邮件或电话号码

javascript - 为什么我的 js 不将 php 输出读取为 json