Rem*_*sen 19 types type-inference typescript
有人可以解释一下为什么给出以下代码:
let f = () => {
throw new Error("Should never get here");
}
let g = function() {
throw new Error("Should never get here");
}
function h() {
throw new Error("Should never get here");
}
Run Code Online (Sandbox Code Playgroud)
推断出以下类型:
f 是 () => neverg 是 () => neverh 是 () => void我期望的类型h是() => never为好.
谢谢!
Rya*_*ugh 27
好问题.不同的是,f和g有功能的表达,在那里h是一个函数声明.当一个函数是throw-only时,never如果它是一个表达式,它将获得类型,void如果它是一个声明.
当然上面的段落实际上没有帮助.为什么函数表达式和函数声明之间的行为存在差异?让我们看看每种情况下的一些反例.
void考虑一些代码:
function iif(value: boolean, whenTrue: () => number, whenFalse: () => number): number {
return value ? whenTrue() : whenFalse();
}
let x = iif(2 > 3,
() => { throw new Error("haven't implemented backwards-day logic yet"); },
() => 14);
Run Code Online (Sandbox Code Playgroud)
这段代码好吗?它应该是!throw当我们认为不应该调用函数时,或者只应在错误情况下调用函数时,编写ing函数是很常见的.但是,如果函数表达式的类型是void,则iif拒绝调用.
所以从这个例子中可以清楚地知道,函数表达式只throw应该返回never,而不是void.实际上这应该是我们的默认假设,因为这些函数符合never(在正确类型的程序中,never无法观察到类型的值)的定义.
never在阅读完前一节之后,你应该说"好了,为什么不把所有的投掷功能都归还never呢?"
简短的回答是,事实证明这是一个重大改变.那里有很多代码(特别是在abstract关键字之前的代码),看起来像这样
class Base {
overrideMe() {
throw new Error("You forgot to override me!");
}
}
class Derived extends Base {
overrideMe() {
// Code that actually returns here
}
}
Run Code Online (Sandbox Code Playgroud)
但是返回的函数void不能替代返回的函数never(记住,在正确类型的程序中,never无法观察到值),因此Base#overrideMe返回会never阻止Derived提供never该方法的任何非实现.
通常,虽然总是抛出的函数表达式经常作为占位符存在,但总是抛出的Debug.fail函数声明非常罕见.表达式经常被别名或忽略,而声明是静态的.函数的声明说throw今天的工作实际上是有可能做一些有用的事情明天; 在没有返回类型注释的情况下,提供更安全的东西void(即不要查看此返回类型)而不是never(即此函数是一个黑洞,将占用当前执行堆栈).