为什么返回类型“null”(或任何其他类型)可以分配给返回类型“void”?

2023-11-21

如您所知,仅在严格模式下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任何其他返回类型都会引发错误)。

这是为什么?这是一个错误还是一个功能?


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

  • TypeScript 常见问题解答条目对于“为什么函数返回非void可分配给函数返回void?"

  • 微软/TypeScript#8581“为什么 () => void 是 () => a 的子类型,如果 void 不是 a 的子类型并且 a 不是 void 的子类型?”

  • 微软/TypeScript#20006“[文档]澄清 void 的语义”

  • 以及许多其他人,例如 microsoft/TypeScript#8240, #8584, #8615, #9603, #19014, etc...


这是预期的行为,而不是错误。 TypeScript 的void类型通常应该代表某种东西unusable, 不必要absent.

一方面,编译器假设您有意且显式地分配任何非undefined键入一个变量或属性类型的void.

另一方面,它处理返回类型为void意思是“调用者不能安全地使用这个函数的返回值”,而不是“这个函数肯定会返回undefined。”因此它可以让你分配一个非void- 在任何地方返回函数值void-返回函数是预期的,因为调用者无论如何都不会检查返回值。

从表面上看,这两种情况是不一致的;一般来说,由于返回类型的协方差, 方式()=>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显式返回回调函数void- 差不多。其中任何一个都会损害生产力。

因此,在这种情况下,实用性和开发人员生产力胜过健全性和一致性。这种权衡在语言中很常见。严格的健全性和类型安全并不是 TypeScript 的设计目标之一。实际上,打字稿设计Non-Goal#3 是

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


Playground 代码链接

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么返回类型“null”(或任何其他类型)可以分配给返回类型“void”? 的相关文章

随机推荐

  • 如何在Android中将彩色图像变成黑白图像

    我想知道当我在android中向用户显示彩色图像 我从网上下载的 时如何将其转换为黑白图像 有人能在你的 Android 作品中发现这个要求吗 请告诉我 谢谢 拉克什曼 您好 您可以使用对比度使图像变为黑白 看代码 public stati
  • C# - 检测人脸并裁剪图像

    我正在写一个HttpHandler在 C 中 它提供调整大小的图像等等 没问题 我们有数百万个处理程序可以用作参考 问题是我的用户照片是用 传统 尺寸拍摄的 如 4 3 和 16 9 但该处理程序需要以照片 ID 尺寸 4 厘米 x 3 厘
  • 使用 Byte Buddy 在运行时添加方法注释

    几天来我一直在寻找 如何在运行时向方法添加注释 的答案 并找到了这个名为 Byte Buddy 的很棒的工具 并使用了它 但仍然无法使其按照我的需要工作 我确信从这个问题来看它一定能够做到这一点Byte Buddy 可以在运行时创建字段和方
  • Eclipse pydev 自动建议在某些情况下不起作用

    我的问题可能很愚蠢 我希望有人成功解决这个问题 有时我在自动完成框中看不到正确的建议 Eclipse 3 5 2 PyDev 1 5 7 例如 import email fp open my eml rb msg email message
  • 如何在 BigQuery 中获取两个数组的交集

    我有这样的数据 id col1 col2 1 1 2 2 3 2 4 4 6 6 7 我想要这样的数据 id col3 1 2 2 6 有什么聪明的解决方案吗 您可以使用INTERSECT DISTINCT build example ta
  • 获取文件的最后n行,类似于tail

    我正在为 Web 应用程序编写一个日志文件查看器 为此我想对日志文件的行进行分页 文件中的项目基于行 最新项目位于底部 所以我需要一个tail 可以读取的方法n线从底部开始并支持偏移 这是我想出的帽子 def tail f n offset
  • gwt 序列化策略托管模式不同步

    在托管模式下运行 GWT 应用程序 gwt 2 0 4 时 调用在远程 Tomcat 上运行的 RPC 方法时 出现 GWT 序列化异常 INFO GwtRpcEventSrvc ERROR The serialization policy
  • 阿帕奇骆驼和杰克逊

    我正在尝试 apache camel 并且设置了一个基本路由 通过 http4 组件调用 http 服务 通过 unmarshal json JsonLibrary Jackson 转换结果 然后打印出部分响应在 bean 组件中 我遇到的
  • 在 C++ 中使用“this”关键字[重复]

    这个问题在这里已经有答案了 可能的重复 在 C 中过度使用 this 是否会产生代码异味 什么时候应该在 C 中使用 this 关键字 有什么理由使用这个 gt 在 C 中 是关键字this通常省略 例如 Person Person int
  • python:扩展 ASCII 代码

    你好 我想知道如何在 python 中附加然后打印扩展的 ASCII 代码 我有以下内容 code chr 247 li li append code print li python 打印输出的结果是 xf7 而它应该是除号 如果我直接简单
  • Angular2 错误 - 是否包含平台模块(BrowserModule)?

    我只是想运行一个简单的index html 页面Angular2 但它在控制台中向我显示了 zone js 中的错误 Unhandled Promise rejection No ErrorHandler Is platform modul
  • MySQL Workbench“正在获取...”——无法浏览数据库

    我最近遇到了很多问题 基本上是自从我上次升级 XAMPP for OSX v1 7 3 和 或我的 MySQL GUI 工具以来 使用MySQL工作台 v5 2 44 我可以很好地连接到在 XAMPP 中运行的数据库 但尝试浏览任何数据库
  • 实体框架选择上个月记录

    我有员工工资表 其中包含 public partial class S EmployeeSalary public int SalaryId get set public int TypeId get set public int User
  • iOS Apple 开发者会员中心 - 如何代表客户提交应用程序

    我需要代表客户提交应用程序 但我只有团队管理员权限 没有团队代理访问权限 我如何通过 Xcode 为他们提交应用程序 我是否必须拥有团队代理的用户名 密码才能执行此操作 作为管理员 您几乎可以做所有事情 有一张图片 Surprisingly
  • 使用 C# 自动生成字母数字唯一 ID

    字符串总长度为 5 个字符 我有一个场景 ID 开头 A0001 并以 A9999 结尾 B0001 至 B9999 直至 F0001 至 f9999 在那之后 然后从 FA001 到 FA999 FB001 至 FB999 直至 FFFF
  • .NET 3.5/VS 2008 上 ASP.NET Web 服务的自定义 HTTP 基本身份验证

    我正在重构一个工作的 ASP NET Web 应用程序 以使用 ASP NET Web 服务公开 Web 服务接口 根据Web 服务身份验证 最佳实践 通过 https 进行基本身份验证是可行的方法 让我们假设它是 而不是做 WS Secu
  • 没有这样的元素:无法在生产环境中使用 chromedriver 和 Selenium 定位元素

    我的 selenium chromedriver 有问题 我无法弄清楚是什么原因造成的 几周前 一切都工作正常 突然这个错误开始出现 问题来自以下函数 def login browser try browser get some url u
  • Ubuntu 上 Boost program_options 代码中的链接错误

    我在 ubuntu 10 04 上安装了 boost sudo apt get install libboost dev 我想之后我不需要设置任何 I 和 L 标志 所以我编译我的代码 g test cpp 这是我的测试 cpp inclu
  • iOS - 倒车视频文件 (.mov)

    要求 听起来没什么不同 但这就是我想要实现的目标 我想反向制作电影 mov 文件 就像我们倒带电影文件一样 我还想保持与我的视频所包含的相同的帧速率 注意 我不仅仅想以相反的顺序播放视频文件 我想生成以相反顺序播放的新电影文件 我的探索 我
  • 为什么返回类型“null”(或任何其他类型)可以分配给返回类型“void”?

    如您所知 仅在严格模式下undefined可分配给类型void 所以如果你尝试 declare let void void void null error void 5 error 你会得到错误 type 不可分配给 void 类型 但如果