编译器通常不会根据输入的特定值来推断函数返回类型。控制流类型分析 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