typescript - 使用 Typescript 从 switch case 返回类型推断

标签 typescript typescript-typings typescript-generics

函数类型

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()

当使用 chosenFN 时,它应该显示属于 switch case 的函数类型,而不是显示所有类型的交集。

我错过了什么? 我认为由于使用的函数在 switch case 内部,它会根据传递的参数推断出正确的类型。

谢谢, 热南

最佳答案

编译器通常不会根据输入的特定值来推断函数返回类型。 Control flow type analysis用于缩小函数实现中具体类型变量的类型,因此 switch 语句用于了解 options 恰好是 op2(例如)在相关的 case block 中,但是控制流分析对函数的返回类型没有太大作用。

通常,函数的推断返回类型是从函数返回的所有类型的联合,与控制流分析无关。这意味着 test() 的签名被推断为类似于 function test(options: Options): fn01 | fn02 | fn03 |空

当你去实际调用fn01 | 类型的函数时fn02 | fn03 | null,你会遇到麻烦。用the --strictNullChecks compiler option上,您根本无法调用它(您可能应该使用--strict 编译器选项,因为它们会捕获错误)。

假设你有一个fn01 |类型的函数fn02 | fn03(并且你已经验证它不是null),你仍然不能真正调用它。对调用函数联合的支持是 improved在 TypeScript 3.5 中,但是,您可以传递给函数联合的唯一安全的东西是其参数的交集。交集 string & string & number 没有成员(在 JavaScript 中没有值既是 string 又是 number),这意味着它是从不,因此它是完全不可调用的。


所以,这就是它不起作用的原因。要修复它,您要么必须使用 function overloads , 或者将函数注释为 generic ,其中 options 是通用类型 O extends Options

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

泛型类型有可能更安全,但当您使用 switch 时就不是这样了,它公开了一个 current limitation of TypeScript因此,控制流分析无法缩小泛型变量的类型。

最安全的方法是使用映射对象而不是 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

Link to code

关于typescript - 使用 Typescript 从 switch case 返回类型推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58673034/

相关文章:

javascript - 如何在 typescript 中描述简单的 Just 仿函数的接口(interface)?

typescript - 输入 Object.fromEntries(new FormData(form))

reactjs - Typescript + Webpack 项目中缺少源映射

javascript - typescript :如何使用其值为数组中值子集的键定义接口(interface)?

javascript - Angular 2 - 如何从 ControlGroup 访问子组件

javascript - 如何在 index.d.ts typescript 定义文件中引用 Redux 类型?

typescript - 从可空类型中提取不可空类型定义

带有函数参数的 typescript 泛型

angular - 自动对焦只工作一次

typescript - 如何防止分配相似的类型?