TypeScript中函数参数推断为never但传入参数合法的类型问题求解
解决TypeScript泛型工厂函数与参数的类型匹配问题
问题分析
你的代码中,test函数的泛型T受boolean约束,TypeScript推断factory()返回值时会将其解析为A | B联合类型。由于A和B的参数类型'A'与'B'无交集,TypeScript会把联合函数的参数类型推断为never,导致f(funcArg)报错——尽管funcArg的ArgType<T>理论上和f的参数类型完全对应,但TypeScript无法自动关联两者的泛型依赖关系。
解决方案
核心思路是让factory()的返回类型与泛型T保持显式条件关联,避免被解析为无差别的联合类型,以下是两种可行方案:
方案1:显式定义useComposable的返回类型
将useComposable的返回类型抽离为泛型条件类型,让TypeScript保留T与返回函数类型的绑定关系:
type A = (arg: 'A') => void type B = (arg: 'B') => void const a: A = (arg: 'A') => { } const b: B = (arg: 'B') => { } // 显式定义返回类型的泛型条件 type UseComposableReturn<T extends boolean> = { factory: () => T extends true ? A : B; }; function useComposable<T extends boolean>(arg: T): UseComposableReturn<T> { return { factory: () => (arg ? a : b) as T extends true ? A : B, }; } type ArgType<R extends boolean> = Parameters< ReturnType<ReturnType<typeof useComposable<R>>['factory']> >[0] function test<T extends boolean>(composableArg: T, funcArg: ArgType<T>) { const { factory } = useComposable(composableArg); const f = factory(); f(funcArg); // 类型检查通过 }; // 合法调用 test(true, 'A') // 预期不合法(TypeScript会报错) test(true, 'B')
方案2:在test函数中显式关联类型
如果不想修改useComposable,可以在test内部通过泛型条件类型明确f的类型,让TypeScript识别它与funcArg的匹配关系:
type A = (arg: 'A') => void type B = (arg: 'B') => void const a: A = (arg: 'A') => { } const b: B = (arg: 'B') => { } function useComposable<T extends boolean>(arg: T) { type MyType = T extends true ? A : B function factory(): MyType { return (arg ? a : b) as MyType } return { factory } } type ArgType<R extends boolean> = Parameters< ReturnType<ReturnType<typeof useComposable<R>>['factory']> >[0] function test<T extends boolean>(composableArg: T, funcArg: ArgType<T>) { const { factory } = useComposable(composableArg); // 显式关联泛型T与f的类型 type FuncType = T extends true ? A : B; const f = factory() as FuncType; f(funcArg); // 类型检查通过 }; // 合法调用 test(true, 'A') // 预期不合法(TypeScript会报错) test(true, 'B')
原理说明
两种方案都是通过保留泛型条件类型的关联性,避免TypeScript将factory()的返回值解析为A | B联合类型。当类型系统能明确f的类型是基于T的条件分支时,就能自动匹配funcArg的ArgType<T>,从而通过类型检查。
内容的提问来源于stack exchange,提问作者Nicolas D
相关产品推荐
相关产品推荐

