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