TypeScript 类型根据其他参数缩小回调中函数参数的范围

2024-04-01

我正在处理经典的节点回调。例子:

myFunction('foo', (err: Error|null, data?: Buffer) =>{
  if (err) {
    // typeof err is Error
    // typeof data is Buffer|undefined
  } else {
    // typeof err is null;
    // typeof data is Buffer|undefined;
  }
});

我正在尝试定义自己的回调接受函数myFunction。我正在努力实现两件事:

  1. 我希望能够推断出类型data根据类型err
  2. 我希望能够隐式推断输入参数的类型

Example:

// types of err and data are inferred from readFile
readFile('foo', (err, data) => {
  if (err) {
    // typeof err is Error
    // typeof data is undefined
  } else {
    // typeof err is null
    // typeof data is Buffer
  }
}

有什么方法可以在当前的打字稿中实现其中任何一个吗?


通常你会使用一个参数受歧视联盟 https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions类型而不是两个联合类型参数,例如err and data其类型彼此相关。

TypeScript 确实没有太多支持相关表达; see 微软/TypeScript#30581 https://github.com/Microsoft/TypeScript/issues/30581。也就是说,没有一个很好的方法来告诉编译器,虽然err属于类型Error | null而同时data属于类型Buffer | undefined,一些类型的组合err and data是不可能的。您可以使用控制流分析 https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#control-flow-based-type-analysis检查类型err,但不会影响感知类型data...编译器错误地假设它们是独立的表达式。

这是我能得到的最接近的;它大量使用休息和扩展表达式中的元组 https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#tuples-in-rest-parameters-and-spread-expressions你真的必须与编译器斗争才能让它发生:

declare function myFunction(
  someString: string,
  someCallback: (...args: [Error, undefined] | [null, Buffer]) => void
): void;

的类型someCallback是一个只有两个参数的函数,这两个参数要么是类型[Error, undefined]或键入的[null, Buffer]。现在轮到你can使用两个参数回调来调用它,但是您将遇到与已经遇到的完全相同的问题:检查err没有做任何事data:

// can't call it this way
myFunction("oops", (err, data) => {
  err; // Error | null
  data; // Buffer | undefined
  if (err) {
    data; // still Buffer | undefined ????
  }
});

相反,您还必须在回调实现中使用剩余参数:

myFunction("foo", (...errData) => {
  if (errData[0]) {
    const [err, data] = errData;
    err; // Error
    data; // undefined
  } else {
    const [err, data] = errData;
    err; // null
    data; // Buffer
  }
});

这是有效的,因为当你检查时errData[0]您正在检查元组对象的单个属性,编译器将使用控制流分析来缩小范围errData为两种已知类型之一。你只能打破errData出入err and data after支票。


我强烈建议您考虑在回调中切换到单个可区分的联合参数。看看这个解决方案是多么简单:

type Param = { type: "Error"; err: Error } | { type: "Data"; data: Buffer };

declare function myFunction(
  someString: string,
  someCallback: (param: Param) => void
): void;

myFunction("foo", param => {
  if (param.type === "Error") {
    param.err; // Error
  } else {
    param.data; // Buffer
  }
});

这正是你想要的,不需要战斗。


链接到代码 https://www.typescriptlang.org/play/#code/C4TwDgpgBAQgrgMwRATlAvFA3lARohEALigGdgUBLAOwHMoBfAbgFgAod6gQwFsJSwXAMbQAKgAsIAYQA2Ae1L9gASSldqAcQjAA6pWDjRAdzkAFLil7bUpbOyhQAJhCEyL0BHGpDglOdSgeEAAxLx8-agAKewcyOT4AZQoaWhJyKjoAGhiHUnjpLhkZXGEAaxJIgDpqi1pSEgBtAFEUFDkUTKgvZwQaCEcAXSgAHygG6jgizvgkVAGASgwAPigANzlKRxj5knXN1g42BwB6Y6ghdQByYHPCmSh9KANKWyMuEBig0O9ff0iAIjkcjApH+nUiqA6Ti4wC4i3QKywOSgkKYUFOUBabTQowmRWRjhhXDRGJmyBxXWoPT6WyOsUoCCgENaiyRdNi0NhJLO5EoRVgBFQI0p1Oo-SggF4NwD4e8iGDEGPMDjEMeIuKtoMA5Ld+Y9nq93p8QmFflF-gggWCmdVKpCACJE+GI5EMpl2okNAAMCzs7NiQn85DGkM6hNhQ0wbq5yIcqPRZyx7WjnOJcZFEF6YtpHIYKJkih9HIc-uogYaweT4ZRrXtUd9Mda3KgeJkSdDKdJgpQsvlivYcsO3D4AmE0FtLyEVB4NBh-QAqtQIgWnuBoOZLDwMNhl5ASP8Eyh-mjISR94xhThQDuoP8a1xD8mSGShcwYs5XO4oJ4fouvsaItFfTyRJkjoNIQNobJAPyNQihKIRyiZQR1xINdeEdNYNizKAdgw-Z2ENb5wj+M0LU6JDeGWJcHBdSJyJ4SpL2gdBmOvfd-lZJM6JtBtU33WVc3zNlCygLi20bJ8u19fsHAVA5+yAA

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

TypeScript 类型根据其他参数缩小回调中函数参数的范围 的相关文章

随机推荐

  • 如何在IE9中读取二进制数据?

    我正在编写一些 Javascript 代码 这些代码使用 Photoshop 嵌入的路径创建图像的 alpha 蒙版 IMG 标签的 onload 处理程序将调用 Clip this 该函数加载图像的源文件并扫描它 这是设置 functio
  • 我需要帮助向 php 实时搜索添加条件

    我刚刚学习 php 最终学习了本教程http www w3schools com php php ajax livesearch asp 到目前为止 我的 PHP 搜索文件看起来与示例中的相同 但我更改了if strlen q gt 0 t
  • 我可以在 Xcode 4 的 DeviceSupport 文件夹中删除以前版本的 iphone 支持吗?

    在我寻找 Xcode 为何如此之大的过程中 我发现 Developer gt Platforms gt iPhoneOS platform gt DeviceSupport 文件夹的子文件夹占用了很多空间 由于我 显然 只允许在 Xcode
  • 如何检测C++中的溢出?

    我只是想知道是否有一些方便的方法来检测运行时 C 程序中使用的任何默认数据类型的任何变量是否发生溢出 我所说的方便是指 如果每次变量的值发生变化时该变量都在其数据类型的范围内 则无需编写代码来跟踪每个变量 或者如果不可能实现这一点 你会怎么
  • 在 python 中将自定义模块与对象一起序列化

    Problem 假设我有这个模块名为custom module class CustomClass pass 我在脚本中使用这个类来序列化我定义的类的对象custom module import cloudpickle import cus
  • Firebase 身份验证的 Swagger 定义

    任何人都可以提供用于 firebase 身份验证的 Swagger 安全定义的工作示例吗 在后端 使用 firebase admin SDK 验证 firebase ID 令牌 import as admin from firebase a
  • RVM 与 ruby​​ 的本机安装

    我想知道在生产服务器中使用 rvm 是否有任何缺点 我应该选择 RVM 还是本机安装 为什么 不要这样做 错误 也许可以这样做 简单总是有回报的 Rvm是一个开发工具 由于您不会在生产服务器上动态地来回切换 Ruby 版本 因此它没有任何好
  • 找不到工具.jar

    我正在尝试构建 JOGL 的副本 但ant一直给我错误找不到tools jar 所以我在我的 JDK 目录中搜索 但也找不到它 有人可以帮我找到tools jar吗 您确定正在搜索您的JDK目录而不是JRE目录 我希望它在 JDK 中lib
  • startActivityForResult 似乎没有调用 onActivityResult

    当用户单击按钮时 它想要调用对话框 该对话框包含 ListView 中的产品列表 用户选择产品后 它应该转到上一个活动 我已经使用过startActivityForResult 有一些问题 我的调用活动位于选项卡活动组中的正常选项卡活动中
  • 如何解决 MVC 过滤器属性中的依赖注入

    我有一个从 AuthorizationAttribute 派生的自定义属性类 它对控制器操作执行自定义安全性 OnAuthorizationCore 方法依赖于各种其他组件 例如 DAL 来判断用户是否可以调用操作 我正在使用 Autofa
  • 如何在Python中仅初始化一次数据库连接并在运行时重用它?

    我目前正在开发一个巨大的项目 该项目不断执行查询 我的问题是 我的旧代码总是创建一个新的数据库连接和游标 这极大地降低了速度 所以我认为是时候创建一个新的数据库类了 目前看起来像这样 class Database object instan
  • 无法将 varchar 值转换为 int 数据类型

    我有简单的代码 我需要进行简单的操作 column A 100 但我无法将varchar类型转换为int 我的错误是 将 varchar 值 0 27 转换为数据类型 int 时转换失败 SELECT POWIERZCHNIA POWIER
  • stat_contour 无法生成等高线

    我需要通过添加行stat contour to my ggplot ggplot2 阴谋 不幸的是 我无法向您提供应该评估点值的真实数据 然而 另一个易于重现的示例的行为是相同的 testPts lt data frame x rep se
  • TFS 2015 - TF401002:SQL Server 数据库引擎无法将数据库备份保存到路径

    尝试为 TFS 2015 创建计划备份时 我收到以下消息 TF401002 SQL Server 数据库引擎无法将数据库备份保存到路径 share d TFSBackups 请授予 SQL 服务帐户读 写权限访问该文件夹 我似乎找不到适合我
  • Google 应用引擎或查询 (python)

    任何人都可以分享您在应用程序引擎中进行 或 查询的方法吗 假设我有 class A db model db Model valueA db ListProperty basestring 在 valueA 我有 aaa aaa bbb bb
  • Android开发者控制台错误报告

    我发布了一个免费的应用程序 有几个用户发表了评论 说应用程序强制在谷歌的反馈中关闭 当天就有数百次下载 留存率高达 84 Google 在开发者控制台中的错误报告显示有 0 个错误 我从来没有遇到过在控制台中报告任何错误的应用程序 它真的有
  • SQL Server 中子查询的总和

    我有一个查询 里面有一些子查询 我想添加一个求和查询来对它们进行求和 我怎样才能做到这一点 example Id SELECT COUNT FROM table1 LEFT JOIN table2 on as col1 SELECT COU
  • #评估图像数据

    如何使用 Eval 将 sql varbinary 数据 图像 绑定到图像 像这样的东西
  • Homebrew pyenv安装错误dyld:未加载库:/usr/local/opt/readline/lib/libreadline.7.dylib

    在 MacOS Mojave 上从 Homebrew 安装 pyenv 后 尝试安装任何 python 版本时出现构建错误 跑步时pyenv install对于任何版本 构建都会失败并出现错误 dyld Library not loaded
  • TypeScript 类型根据其他参数缩小回调中函数参数的范围

    我正在处理经典的节点回调 例子 myFunction foo err Error null data Buffer gt if err typeof err is Error typeof data is Buffer undefined