Javascript 类型脚本标记的union not type签入开关语句

Javascript 类型脚本标记的union not type签入开关语句,javascript,typescript,types,switch-statement,discriminated-union,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 und

我使用的是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
    }
}
type A={type:“A”}
类型B={type:“B”}
类型Any=A | B
函数get(x:T[“type”]):T |未定义{
开关(x){
案例“x”:返回未定义
默认值:返回未定义
}
}

问题归结为中的
checkSwitchStatement
中的该代码,该代码自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
的类型是受
string
约束的某个类型参数
T
,我们希望能够将其与
“x”
进行比较;已知
T
“x”
都不能分配给另一方,但是
T
可以包括
“x”
。因此,当比较的一端是文字的并集,而另一端不是时,代码将用底层原语类型替换文字的并集。这种情况在您的代码中触发,其中
“x”
是一个文本,
T[“type”]
本身不是一个文本,尽管它受到文本并集的约束

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

如果您认为您以前遇到过错误,可能您正在考虑以下代码。如果可能的话,类型参数上的属性访问类型将根据类型参数的约束急切地解析,因此
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
    }
}
type A={type:“A”}
类型B={type:“B”}
类型Any=A | B
函数get(y:T):T |未定义{
开关(y型){
案例“x”:返回未定义
默认值:返回未定义
}
}

看起来像一个bug,我创建了感谢@artem提交这期文章,我会关注它是的,@McCutchen,我相信你的例子就是我以前看到的。我经常感到惊讶的是,打字机脚本推理很少会失败。我们来看看这个问题会有什么结果。