使用 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 返回进行类型推断 的相关文章

  • 如何跨多个 React Redux 组件使用 requestAnimationFrame 实现游戏循环?

    努力思考最好的解决办法 我可以使用递归调用requestAnimationFrame有一个游戏循环 export interface Props name string points number onIncrement gt void o
  • FP-TS 分支(面向铁路的编程)

    我在尝试使用 FP TS 实现事物时不断遇到的一种模式是 当我的管道涉及到 TaskEither 的分支和合并分支时 合并似乎工作得很好 因为我可以使用sequenceT创建数组并将它们通过管道传输到函数中 然后使用所有这些值 似乎不太有效
  • 使用带有十六进制字符串的 CryptoJS

    我想连接到蓝牙设备 仅通过十六进制字符串进行通信 我需要编码一个 16 字节值 因此我也期望一个 16 字节的值 在我的实现中 CryptoJS 总是返回更长的结果 根据文档 不需要 IV 所有 16 字节数据必须使用当前存储在设备中的客户
  • 在 Angular 上开发时无法自动完成和自动导入

    我已经在 Windows 上安装了最新的 VSCode 然后我安装了 languaje 对 TypeScript 的支持 最后 设置一些编辑器选项并安装一些扩展 编辑器配置 editor fontSize 12 editor minimap
  • 为什么 Angular 4.3 中的 httpclient 返回 Object 而不是 any?

    Angular 4 3 中的新 HttpClient 类似乎又回来了Object代替any默认情况下 鉴于打字稿文档所述 这样做是否有特殊原因 永远不要使用数字 字符串 布尔值或对象类型 这些 类型指的是几乎从未使用过的非原始装箱对象 适当
  • 在 Typescript 中导出函数的返回类型

    我有一个构建对象的函数 如下所示 function toast return a a b b 我可以将函数的类型定义为 type ToastFunctionType typeof toast 这种类型将是 gt a string b str
  • Typescript + Jquery Ajax + 这个

    我正在将一些 javascript 代码移植到 typescript 中 但遇到了一个问题 我有一个 ajax 调用 它将一个对象作为上下文传递 该对象包含一些回调和一些其他信息 这些信息由成功或错误回调读出 指示成功调用应重定向到的位置
  • TypeScript 中类和命名空间的区别

    到底有什么区别classes and namespaces在打字稿中 我知道 如果您创建一个带有静态方法的类 您可以在不实例化该类的情况下访问它们 这正是我猜想的命名空间的要点之一 我还知道你可以创建多个同名的命名空间 并且它们的方法在编译
  • 将 Angular v12 升级到 v13 时出现“模块未找到”错误

    嗨 开发者和贡献者 我正在努力找出以下错误的问题所在 src app models type ModelType ts 2 0 44 错误 找不到模块 错误 导出字段无法解析目录 请求为 当我将 Angular 版本从 v12 升级到 v1
  • 在 TypeScript / Angular 4+ 中将 Enum 键显示为字符串

    export enum Type TYPE 1 Apple TYPE 2 Orange TYPE 3 Banana 当我登录时Type TYPE 1 toString默认情况下会调用方法 console log Type TYPE 1 is
  • Typescript 数组文字语法的差异

    Typescript 允许使用以下任一语法定义数组 var myStrArry1 string or var myStrArry1 Array
  • TypeScript 中 C# 类虚拟成员的等效项

    因此 在 C 中 当我创建模型类和延迟加载内容时 我会执行以下操作 public int User ID get set public int Dept ID get set 然后在我的班级稍远一点的地方 我像这样弹出我的虚拟 public
  • Gulp 和 TS 编译

    我在我的 gulp 文件中定义了任务 gulp task dev build scripts function var tsResult tsProject src pipe sourcemaps init pipe ts tsProjec
  • Typescript 项目引用:处理引用项目的第三方依赖项

    我有一个包含 3 个目录的项目client api and shared The shared目录包含 typescript 类型和定义engine我想与之共享的文件夹client and api 此外 shared目录还需要一些第三方依赖
  • 如何使用“ADDMORE”按钮在 Angular 6 中上传多个文件?

    你好 埃弗龙 我一直在尝试上传上面 图片 用例 我知道当我们只有一个文件时这很容易 但现在的情况不同了 它由带有文件的对象数组组成 现在我的问题是如何使用对象数组渲染 formdata 对象 其中每个对象都包含一个文件 对于动态形式 我使用
  • 尝试为每一行编写测试用例

    已经编写了跳跃方法的测试用例 但当我看到代码覆盖率报告时 它不会进入onloadend方法seat onloadend 在 createSpyObj 中我调用了 loadend 但它仍然没有进入内部 你们能告诉我如何解决它吗 下面提供我的代
  • 为什么抽象类必须实现接口中的所有方法?

    interface BaseInter name string test void abstract class Abs implements BaseInter 在 TypeScript 中 编译器抱怨该类错误地实现了接口 Abs 类型中
  • Angular 2延迟加载模块-服务不是单例

    我已经在我的应用程序中实现了延迟加载模块 app module ts 配置正确 NgModule declarations AppComponent HeaderComponent HomeComponent imports Browser
  • 使用验证器禁用 FormGroup

    I had formArray我的复选框checkboxForm 如果没有复选框 我需要禁用按钮提交checked 我在我的上实现了自定义验证器checkboxForm 这是我尝试过的 Ts file get formReceivedSum
  • React 应用程序 npm 错误代码 ELIFECYCLE

    下面是我的反应应用程序 我尝试过重新安装node module 设置 环境变量 C Windows System32 name my app version 0 1 0 private true dependencies testing l

随机推荐

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

    我只是在练习代码优先新数据库实体框架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