问题描述
谁能解释一下为什么给出以下代码:
Can someone please explain me why given the following code:
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");
}
推断出以下类型:
f
是() =>从不
g
是() =>从不
h
是() =>无效
f
is() => never
g
is() => never
h
is() => void
我希望 h
的类型是 () =>也从不
.
I would expect the type of h
to be () => never
as well.
谢谢!
推荐答案
很好的问题.区别在于f
和g
是函数表达式,其中h
是函数声明em>.当一个函数是 throw
-only 时,如果它是一个表达式,它会得到 never
类型,如果它是一个声明,它会得到 void
类型.
Great question. The difference is that f
and g
are function expressions, where h
is a function declaration. When a function is throw
-only, it gets the type never
if it's an expression, and void
if it's a declaration.
当然上面的段落实际上并没有帮助.为什么函数表达式和函数声明之间的行为存在差异?让我们看看每种情况下的一些反例.
Surely the above paragraph doesn't actually help. Why is there a difference in behavior between a function expression and a function declaration? Let's look at some counter-examples in each case.
考虑一些代码:
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);
这个代码好吗?它应该是!当我们认为不应调用该函数或仅应在错误情况下调用该函数时,通常会编写 throw
ing 函数.但是,如果函数表达式的类型是 void
,则对 iif
的调用将被拒绝.
Is this code OK? It should be! It's common to write a throw
ing function when we believe the function shouldn't be called, or should only be called in error cases. If the type of the function expression were void
, though, the call to iif
would be rejected.
所以从这个例子可以清楚地看出,只有 throw
的函数表达式应该返回 never
,而不是 void
.实际上这应该是我们的默认假设,因为这些函数符合 never
的定义(在正确类型的程序中,无法观察到 never
类型的值).
So it's clear from this example that function expressions which only throw
ought to return never
, not void
. And really this should be our default assumption, because these functions fit the definition of never
(in a correctly-typed program, a value of type never
cannot be observed).
阅读上一节后,您应该说太好了,为什么不是所有的抛出函数都返回 never
呢?"
After reading the prior section, you should be saying "Great, why don't all throwing functions return never
, then?"
简而言之,事实证明这样做是一个重大的突破性变化.有很多代码(尤其是在 abstract
关键字之前的代码)看起来像这样
The short answer is it turned out to be a big breaking change to do so. There's a lot of code out there (especially code predating the abstract
keyword) that looks like this
class Base {
overrideMe() {
throw new Error("You forgot to override me!");
}
}
class Derived extends Base {
overrideMe() {
// Code that actually returns here
}
}
但是返回void
的函数不能替代返回never
的函数(记住,在正确类型的程序中,never
值不能被观察),所以让 Base#overrideMe
返回 never
可以防止 Derived
提供任何非 never
实现那个方法.
But a function returning void
can't be substituted for a function returning never
(remember, in a correctly-typed program, never
values cannot be observed), so making Base#overrideMe
return never
prevents Derived
from providing any non-never
implementation of that method.
通常,虽然总是抛出的函数表达式经常作为Debug.fail
的占位符存在,但总是抛出的函数声明是非常稀有.表达式经常被别名或忽略,而声明是静态的.今天throw
的函数声明实际上很可能在明天做一些有用的事情;在没有返回类型注释的情况下,提供更安全的方法是 void
(即暂时不要查看此返回类型)而不是 never
(即此函数是一个会吃掉当前执行堆栈的黑洞).
And generally, while function expressions that always throw often exist as sort of placeholders for Debug.fail
, function declarations that always throw are very rare. Expressions frequently get aliased or ignored, whereas declarations are static. A function declaration that throw
s today is actually likely to do something useful tomorrow; in the absence of a return type annotation, the safer thing to provide is void
(i.e. don't look at this return type yet) rather than never
(i.e. this function is a black hole that will eat the current execution stack).
这篇关于TypeScript 从不进行类型推断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!