为什么TypeScript同时具有`void`和`undefined`?

时间:2019-11-15 22:27:20

标签: typescript undefined void

在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的别名?它根本不需要存在吗?

2 个答案:

答案 0 :(得分:5)

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不是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;
  };
}

答案 1 :(得分:0)

因此,从这个角度来看,number | void应该解析为void对吗? 由于您不应观察到类型void的值,因此由于void|number部分的原因,您也无法检查number是否实际上是void。任何值。也可能是一个不应该被观察到的数字。