void 和undefined 之间的关系有点混乱,因为它们的使用方式有一些相互不一致的地方。大致上,void 是指不返回有意义值的函数的返回类型。但是,当您开始将其分开时,它会变得很粘。
从void-returning 函数的调用者的角度来看,这意味着用返回值做很多事情本质上是一个错误:
declare let voidReturn: () => void;
let v = voidReturn();
v.foo; // Property 'foo' does not exist on type 'void'
v + 2; // Operator '+' cannot be applied to types 'void' and 'number
由于调用者本质上承诺不检查 void-returning 函数的返回值,因此在其位置分配任何函数都是安全的,无论它是否返回值:
voidReturn = () => 123; // okay
请参阅the handbook documentation about returning void 了解允许这样做的原因。
无论如何,从这个角度来看,你真的不应该看到undefined 特别可分配给void。您不能真正使用void 返回值,就好像它是undefined(因为它很可能是123,如您所见),并且类型检查函数类型在某种意义上将几乎任何东西都视为可分配给void () => T 可分配给所有T 的() => void。
从void-returning 函数的调用者的角度来看,好像void 就像the unknown type。但是void 比unknown 早了很多。
另一方面,从void-returning 函数的实现者的角度来看,编译器认为返回任何定义的值都是错误的:
function voidReturn2(): void {
return 123; // error!
// Type 'number' is not assignable to type 'void'.(2322)
}
这与voidReturn = () => 123 分配的函数表达式几乎相同,但是这个被认为是错误的。是的,这在技术上是不一致的。在需要void-returning 函数的地方使用现有的事物返回回调函数很有用,并且一直在发生,如上述手册文档中所述。但是,直接返回一个定义的值,其中应该是 void 值,它的用处不大,而且更多地表明了错误。
无论如何,这意味着你在实现void返回函数时不应该返回任何东西:
function voidReturn3(): void { } // okay
没有返回语句的函数等效于仅以return; 结尾的函数。所以编译器可能也应该接受这一点,它确实:
function voidReturn4(): void {
return;
} // okay
在return 之后没有指定值的函数等效于返回undefined 的函数。所以编译器也应该接受这一点,它确实:
function voidReturn5(): void {
return undefined;
} // okay
而那就是为什么undefined可以分配给void。当您有一个应该是 void 类型的表达式时,唯一可接受的值是 undefined。
当然,它并不是真正一致的,并且会导致一些可能不受欢迎的奇怪行为。 void 返回函数的调用者应该忽略它们的返回值。但他们不必这样做,然后他们可能会有一个void 类型的变量在附近徘徊。您可以将undefined 分配给它,但不能分配123:
let w = voidReturn();
w = 123; // error
w = undefined; // okay, but that's weird
哦,好吧。
您还可以查看 microsoft/TypeScript#25481 和其他有关 void 奇怪行为的 Stack Overflow 问题,例如 Why does TypeScript have both `void` and `undefined`? 或 why is return type `null` (or any other type) assignable to return type `void`? 或 Typescript: void union type。
Playground link to code