使用 Typescript 从 switch case 返回进行类型推断

2023-12-21

函数的类型

type fn01 = (name: string) => void
type fn02 = (age: string) => void
type fn03 = (description: number) => void

我有这样一个案例:

type Options = 'op1' | 'op2' | 'op3'

const test = (options) => {
    switch(options) {
          case 'op1':
            return fn01
          case 'op2':
            return fn02
          case 'op3':
            return fn03
          default
            return null;
        }
    }

功能使用:

const chosenFN = test('op1');

choseFN()

当使用 selectedFN 时,它应该显示将落入 switch case 的函数的类型,而是显示所有这些函数的交集。

我缺少什么? 我认为由于使用的函数位于 switch case 内部,因此它会根据传递的参数推断出正确的类型。

谢谢, 勒南


编译器通常不会根据输入的特定值来推断函数返回类型。控制流类型分析 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#control-flow-based-type-analysis作用是缩小函数实现中具体类型变量的类型,因此switch声明的目的是为了知道options正是op2(例如)在相关的case块,但控制流分析对函数的返回类型没有太大作用。

通常,函数的推断返回类型将是所有类型的并集return从函数中编辑,与控制流分析无关。这意味着签名test()被推断为类似的东西function test(options: Options): fn01 | fn02 | fn03 | null.

当你实际调用类型的函数时fn01 | fn02 | fn03 | null,你会遇到麻烦。和the --strictNullChecks编译器选项 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#--strictnullcheckson,你根本不能调用它(而且你可能should使用--strict编译器选项,因为它们捕获错误)。

假设你有一个类型的函数fn01 | fn02 | fn03(并且您已验证它不是null),你仍然不能真正调用它。支持调用函数并集improved https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-3.html#improved-behavior-for-calling-union-types在 TypeScript 3.5 中,但是,您可以传递给函数联合的唯一安全的东西是路口其参数。还有路口string & string & number没有成员(没有值既是string and number在 JavaScript 中),这意味着它是never,因此它是完全无法调用的。


所以,这就是为什么它不起作用。要修复它,您必须使用函数重载 https://www.typescriptlang.org/docs/handbook/functions.html#overloads,或将函数注释为generic https://www.typescriptlang.org/docs/handbook/generics.html, where options是泛型类型O extends Options.

重载很容易,但它们并不是真正的类型安全。

泛型类型有可能更加类型安全,但当您使用时则不然switch,这暴露了一个TypeScript 当前的限制 https://github.com/microsoft/TypeScript/issues/13995由此,控制流分析无法缩小泛型变量的类型。

最安全的方法是使用映射对象而不是switch陈述:

const test = <O extends Options>(options: O) => ({
    op1: fn01,
    op2: fn02,
    op3: fn03
}[options]);

这被正确地推断为一个通用函数,其中每个输入类型映射到特定的函数输出类型:

const chosenFN = test('op1'); // (name: string) => void
chosenFN("okay") // okay
test('op2')("age is a string I guess"); // okay
test('op3')(8675309); // okay

链接到代码 https://www.typescriptlang.org/play/#code/CYUwxgNghgTiAEYD2A7AzgF3gMxQBgEYAueAChSgFsQTMYBLFAcwEp4BeAPngDcl7gAWABQoSLATJ0WXHgBMJUlCY14dRqw7c+AkWOhxEqTDnwBmRaDRgGABwz1UJFAFdKAIxAw2XXvyHCIhgAnrYIAPL2jugc8ADkSLYEcfAAPvGJcinpCbZmcSKFwlImGCAm7PAAPOHwIAAeZSjAaPCRDsacpIkd6CThPtykAN4i8OPwicSmhAA0YxOZJLJy88ITk3nL5iIAvgDaPdFoALosANxFJVhgABZIaCAoAGIAcrFlmKS5yRfwAPT-MgUai0DAMZiDPy6Yr3R4vV6kABESAA1lBgki2IDJujgkFyhhvpk4ixkcoEPRWlA1OCNPAAJLwJgucpoLHnAFAtEYglfXL5MkADgAbAB2ACsZjwAE4-jiecEgA

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

使用 Typescript 从 switch case 返回进行类型推断 的相关文章

随机推荐

  • 实体框架中可以有没有主键的表吗?

    我只是在练习代码优先新数据库实体框架msdn http msdn microsoft com en us data jj193542 我想知道是否可以在代码中先创建一个没有主键的表新数据库EF EF 可以用数据库做的事情和数据库可以做的事情
  • 为什么 MVC3 没有搭建我的外键列

    我尝试首先使用代码将 MVC 3 与 EF 4 1 结合使用 并遵循 Scott Guthries 教程http weblogs asp net scottgu archive 2011 05 05 ef code first and da
  • 将带有换行符和制表符的 python 字符串转换为字典

    我对我遇到的这个特殊问题有点困惑 我有一个可行的解决方案 但我认为它不太Pythonic 我有一个像这样的原始文本输出 Key 1 Value 1 Key 2 Value 2 Key 3 Value 3a Value 3b Value 3c
  • PHP 以数组形式读取特定的 csv 文件列

    我是 PHP 新手 希望能够读取有两列的 csv 文件 一列是数字 有点像 ID 另一列保存整数值 我查找了 fgetcsv 函数 但无法找到从 csv 文件读取特定列的方法 我想仅从第二列获取所有值 没有标题 有办法做到这一点吗 这是我到
  • Android:单击网页视图中页面中的链接

    我在android web视图中包含了一个web应用程序 并且网页中有一个链接可以打开其他网站 当单击该链接时 第一次单击可以正常工作 但是当第二次单击时 找不到该网站 代码是 Override public boolean shouldO
  • Wix React-native-navigation 更改 Tab 和推屏

    如何同时切换选项卡和推送屏幕 当按钮被按下时 我想切换到另一个选项卡并推送一个新屏幕 是否可以 class Example extends Component buttonHandler gt this props navigator sw
  • Hive 如何存储数据(从 HDFS 加载)?

    我对 Hadoop HDFS 和 Hbase 和 Hadoop 生态系统 Hive Pig Impala 等 相当陌生 我对 Hadoop 组件 例如 NamedNode DataNode Job Tracker Task Tracker
  • 尝试访问EC2实例超时的可能原因

    我无法通过 SSH 连接到我的实例 操作超时 可能的原因是什么 我该如何解决 重新启动通常需要很长时间才能生效 并且可能会让事情变得更糟 更新 这与权限无关 我可以正常登录 我怀疑这可能是因为内存问题 我遇到了同样的问题 解决方案最终是添加
  • 如何让 JUnit 测试等待?

    我有一个JUnit测试 我想同步等待一段时间 我的 JUnit 测试如下所示 Test public void testExipres SomeCacheObject sco new SomeCacheObject sco putWithE
  • x86 内核中的键盘 IRQ

    我正在尝试编写一个非常简单的内核以用于学习目的 在阅读了一堆有关 x86 架构中的 PIC 和 IRQ 的文章后 我已经明白了IRQ1是键盘处理程序 我使用以下代码来打印按下的键 include port io h define IDT S
  • 使用“开始于”目录获取 Windows .lnk 快捷方式的目标

    我正在尝试检索 Windows lnk 快捷方式的目标路径 但根据 lnk 文件的属性 目标 不是实际文件路径 我正在使用 IWshRuntimeLibrary 并且我正在访问的快捷方式对象的类型为 IWshShortcut WshShel
  • Htaccess Apache END 标志替代方案

    我为小型项目编写了一个小型框架 PHP 除了定义的路径外 它应该重定向到index php path 1 有了 END 标志 这就不成问题了 但自 Apache 2 3 以来 END 标志仍然存在 并且该脚本也应该可以在 apache 2
  • 如何在电子邮件中嵌入图像

    我需要在电子邮件中嵌入图像 我该怎么做 我不想使用第三方工具 也不对特定于语言的答案感兴趣 但它是 PHP 以防您想知道 我只对生成的电子邮件正文的格式感兴趣 如您所知 作为电子邮件传递的所有内容都必须文本化 您必须创建包含多部分 mime
  • 如何在 SQLite 触发器中使用 WITH 子句

    我正在尝试在 SQLite 数据库中创建某些内容的日志 我正在使用触发器执行此操作 但我需要插入多个日志记录 并且它们都需要具有相同的时间戳 为了做到这一点 我正在尝试使用WITH子句来获取当前时间戳 然后我可以在多个地方使用它 我的声明看
  • Instagram API 无需身份验证

    是否可以使用 Instagram API 并创建一个网络应用程序 通过主题标签显示一些图像 而无需用户验证自己的身份 我正在使用 ASP NET 来开发网站 不确定标签 但您可以使用 JSON 格式下载任何 Instagram 用户照片源
  • 如何制作 MKAnnotationView 下降动画?

    我有一个自定义 MKAnnotationView 我自己在 viewForAnnotation 中设置图像 如何像使用 MKPinAnnotationView 一样为其掉落设置动画 我的代码是 MKAnnotationView mapVie
  • Keras 使用预训练嵌入初始化大型嵌入层

    我正在尝试使用预训练的嵌入和自定义语料库在 Keras 2 中使用 Tensorflow 后端重新训练 word2vec 模型 这就是我使用预训练嵌入来初始化嵌入层的方法 embedding Embedding vocab size emb
  • 想要有效地克服 Boost.Interprocess 共享内存中映射中关键类型之间的不匹配

    我正在使用 Boost Interprocess 在共享内存中创建一个映射 在本示例中从字符串到字符串 编译器似乎想强迫我在从映射检索期间在 托管段只是为了 不必要地 包含查询项 我希望能够 通过将映射的键与非共享内存中已有的实例进行匹配
  • 奥里利亚的全球职能

    我试图弄清楚如何在 Aurelia 中存储类似 全局 的函数 我已经按照这个教程 http blog durandal io 2015 04 24 aurelia custom elements and content selectors
  • 使用 Typescript 从 switch case 返回进行类型推断

    函数的类型 type fn01 name string gt void type fn02 age string gt void type fn03 description number gt void 我有这样一个案例 type Opti