在TypeScript中,您可以将函数注释为返回void
:
function fn1(): void {
// OK
}
function fn2(): void {
// Error
return 3;
}
您还可以注释一个函数以返回undefined
:
function fn3(): undefined {
// OK
return;
}
function fn4(): undefined {
// Error
return 3;
}
因此,如果您调用返回void
的函数,则总是会获得undefined
值。但是您不能编写以下代码:
function fn5(): void {
}
let u: undefined = fn5(); // Error
为什么void
不只是undefined
的别名?它根本不需要存在吗?
void
在函数返回类型中具有特殊含义,并且不是undefined
的别名。这样想是非常错误。为什么?
void
的意图是函数的返回值将不会被观察。这与将为undefined
完全不同。重要的是要有这种区别,以便您可以正确描述forEach
之类的功能。让我们考虑一下Array#forEach
的独立版本,在回调返回位置用undefined
而不是void
编写:
declare function forEach<T>(arr: T[], callback: (el: T) => undefined): void;
如果您尝试使用此功能:
let target: number[] = [];
forEach([1, 2, 3], el => target.push(el));
您会收到一个错误:
类型“数字”不可分配给类型“未定义”
这是正确的错误-您说您想要一个返回值undefined
的函数,但实际上您提供了一个返回值number
的函数,因为这就是Array#push
返回的原因!
使用void
表示forEach
承诺不使用返回值,因此可以通过返回任何值的回调来调用它
declare function forEach<T>(arr: T[], callback: (el: T) => void): void;
let target: number[] = [];
// OK
forEach([1, 2, 3], el => target.push(el));
为什么不只使用any
?如果您实际上是实现forEach
的人,那么您真的不希望这样-浮动any
是一件很危险的事情,很容易导致类型检查失败。
推论是,如果您有某个函数表达式的返回类型为void
,则您不能确定地说调用该函数的结果是undefined
。
void
是not undefined
的别名,并且类型void
的表达式可能具有any值,而不仅仅是undefined
在函数body中,其返回类型显式列出为void
,即使不会造成类型系统冲突,TypeScript也会阻止您“意外”返回值。这有助于捕获重构中出现的错误:
// Old version
function fn(arr: number[]): void {
const arr1 = arr.map(x => {
return 3;
});
}
// New version
function fn(arr: number[]): void {
for (const x of arr) {
// Oops, meant to do something else
return 3;
};
}