为什么类型检查器允许此代码?

时间:2019-11-07 09:10:27

标签: typescript

这样的代码可以通过类型检查吗?

function infiniteLoop(): never {
    while (true) {
    }
}
let x = infiniteLoop();

x如何存在并因此居住在never类型中?

3 个答案:

答案 0 :(得分:2)

never是一种类型。任何变量都可以具有这种类型(因为任何变量都可以具有任何类型)。因此,当您说let x = infiniteLoop()时,Typescript推断x的类型为never。很好。

但是,这就是有用的地方,它阻止您稍后使用x。那才是真正的语义错误。

有关更多示例,请参见this explanation

更一般地说,您不能从类型系统中期望它会静态处理无限循环检测。这是因为它是类型系统的undecidable problem

当您显式提供never类型提示时,

Typescript方法可以静态地查明不需要的行为。具体来说,它可以防止您使用显式声明为无止境的计算结果(或从声明为无止境的计算返回)。

答案 1 :(得分:1)

我将尝试回答自己的问题。 never seems to be "bottom" type。但是“底部”是任何其他类型的子类型:

function f() : never
{
    return (1 as never); // but is not true for "as void".
}
  

底部是各种类型的居民(尽管有一些警告)   关于未装箱种类的类型),无论何时何处都可以使用底部   该类型的值将为(here)。

因此,infiniteLoop()可以返回never,任何类型都包含never作为其子类型,甚至可以声明它:

let x:never;

并且由于它是任何其他类型的子类型,因此可以将它们的值“广播”(使用as)到never。但是无法将超集分配给它的子集,例如将Triangle类型设置为never-这就是我们在这里得到错误的原因:

type Shape = Square | Rectangle | Circle | Triangle;

function assertNever(x: never): never {
    throw new Error("Unexpected object: " + x);
}
function area(s: Shape) {
    switch (s.kind) {
        case "square": return s.size * s.size;
        case "rectangle": return s.height * s.width;
        case "circle": return Math.PI * s.radius ** 2;
        default: return assertNever(s); // error here if there are missing cases
    }
}

答案 2 :(得分:0)

我认为因为类型确定。如果您想查看消息this code will not be never reach because of infinity loop的类型,可以安装声纳皮棉,它应该显示错误