【问题标题】:why is return type `null` (or any other type) assignable to return type `void`?为什么返回类型“null”(或任何其他类型)可分配给返回类型“void”?
【发布时间】:2021-01-14 14:53:47
【问题描述】:

您可能知道,在严格模式下,只有 undefined 可以分配给类型 void。所以如果你尝试:

declare let _void: void;
_void = null; // error
_void = 5; // error

你会得到错误

[type] 不可分配给类型 void。

但是如果你尝试这个作为返回类型,一切都会好的:

declare let voidReturn: () => void;
declare let nullReturn: () => null;
declare let numReturn: () => number;

voidReturn = numReturn;
voidReturn = nullReturn;

void 在此处的行为类似于 any,因为它可以容纳任何类型(但它只能以一种方式工作 - 将 void 分配给任何其他返回类型都会引发错误)。

这是为什么呢?这是错误还是功能?

【问题讨论】:

  • this:github.com/Microsoft/TypeScript/wiki/… 部分回答了我的问题。
  • 似乎void 的整个概念被打破了,因为你不能从函数中返回任何内容。如果您不在函数中使用return,该函数仍会返回undefined。这实际上是在语言中添加了除了nullundefined 之外的第三个化身。不聪明。 void 不应该被使用。
  • void 作为函数返回类型并不意味着该函数返回“无”。这意味着调用者不应使用函数的返回值。它是“坏”还是“不聪明”主要是见仁见智,但它是一个功能而不是一个错误。一般来说,语言维护人员会仔细考虑此类功能,并且不一致通常代表不同用例之间的权衡。

标签: typescript


【解决方案1】:

可以在以下位置找到此问题的规范答案:


这是预期的行为,而不是错误。 TypeScript 的 void 类型通常应该代表unusable的东西,不一定absent

一方面,编译器假定您故意显式地将任何非undefined 类型的值分配给@987654337 类型的变量或属性 可能是错误的@。

另一方面,它将返回类型为void 的函数视为“调用者不能安全地使用此函数的返回值”,而不是“此函数肯定会返回undefined”。因此,它允许您在任何需要 void-returning 函数的地方分配一个非void-returning 函数值,因为调用者无论如何都不会检查返回值。

从表面上看,这两种情况是不一致的;一般而言,由于covariance of return types,当且仅当A 可分配给B 时,()=>A 类型才可分配给()=>B。这与void 不同,这可能是您对这种情况感到困扰的原因。


但尽管前后不一致,但无论好坏,它都是有意的。原因是能够忽略回调返回值非常有用,尤其是对于碰巧有副作用和返回值的箭头函数。这里的首选示例是Array.prototype.push(),它会改变你调用它的数组并返回它的新长度。我想打电话

const arr1 = [4, 5, 6];
const arr2 = [1, 2, 3];
arr1.forEach(v => arr2.push(v))

没有forEach() 对我生气,因为push() 返回一个number 而不是承诺的void

interface Array<T> {
    pedanticForEach(cb: (val: T) => undefined): void;
}
Array.prototype.pedanticForEach = Array.prototype.forEach;

arr1.pedanticForEach(v => arr2.push(v)); // error!
arr1.pedanticForEach(v => (arr2.push(v), undefined)); // okay
arr1.pedanticForEach(v => void arr2.push(v)); // okay

但是void 值本身的类似操作用处不大。没有一个常见的用例是有人真正想将number 值显式分配给void 类型的变量。当你这样做时,它可能是一个错误。

为了使其保持一致,他们要么必须允许这个可能的错误,要么强迫人们用明确的void-ish 包装他们的非实际-void 返回回调函数。其中任何一种都会损害生产力。

因此,在这种情况下,实用性和开发人员生产力胜过稳健性和一致性。这种权衡在语言中很常见;严格的可靠性和类型安全不是 TypeScript 的设计目标之一。其实TypeScript Design Non-Goal#3就是要

应用健全或“可证明正确”的类型系统。相反,在正确性和生产力之间取得平衡。


Playground link to code

【讨论】:

  • 您是否同意将void 引入语言,更好的想法是让undefinedvoid 一样有点不一致?因此,如果我有一个返回 undefined 类型的变量,我可以为其分配一个返回任何其他类型的函数:let f: () =&gt; undefined = () =&gt; whateverValue。仅返回 undefined 是一个足够好的指标,表明您不希望使用返回值,因为 undefined 本质上是无用的。如果在语言中添加null 是一个十亿美元的错误,那么添加void 也是一个错误恕我直言。
  • 好吧,undefined 有用;你确实需要在使用它们之前检查它们是否是undefined(使用--strictNullChecks),而你不应该对void类型的值做任何事情,甚至不检查它平等。 [1,2,3].find(callback) 返回 number | undefined,如果我可以用任何东西代替它的结果,你就会遇到问题。
  • 我对@9​​87654374@-vs-void 的看法,或者语言中的特定设计选择是否是“错误”或本可以做得更好,而显然正确 ?,通常不是 SO 的主题。在很多情况下,我不同意语言设计者的选择,但一般来说,他们做出这些选择的原因(有时可以在 GitHub 问题中发现)与支持用例有关,而我并不关心他们做。在转向黑暗面之前,我花了一段时间希望 TS 完全健全。
  • 返回 number | undefined 实际上等于返回 number | void - void 在这里将其含义从 anything 更改为 undefined。这是一个可能返回有用信息(number)或不返回有用信息的函数示例。空值仅在其他值的上下文中才有意义。如果一个函数只返回 void 或只是 undefined 或只是 null 那里没有信息。您不必检查或使用它们,因为您已经知道那里有什么。
猜你喜欢
  • 2021-07-27
  • 1970-01-01
  • 2015-06-29
  • 1970-01-01
  • 1970-01-01
  • 2018-01-04
  • 2022-12-11
  • 1970-01-01
  • 2021-09-23
相关资源
最近更新 更多