含多泛型回调的函数调整参数顺序后泛型类型推断失效
解决TypeScript shapeAdapter函数回调顺序影响类型推断的问题
问题背景
我在TypeScript中实现了类型安全的shapeAdapter函数,它接收原始对象original、转换函数adapt、还原函数revert。当前存在的问题:
- 当
adapt排在revert之前时,类型推断正常,revert的transformed参数能正确匹配adapt的返回类型 - 调换两者顺序后,
revert的transformed参数会被推断为unknown,而非预期类型 - 尝试过
NoInfer工具类型,但未解决问题
原代码定义
function shapeAdapter<Original, Transformed>(props: { original: Original; adapt: (original: NoInfer<Original>) => Transformed; revert: (transformed: NoInfer<Transformed>) => NoInfer<Original>; }) { throw new Error("Implementation does not matter") }
正常调用示例(顺序正确)
shapeAdapter({ original: { value: 1 }, adapt: (original) => original.value, revert: (transformed) => ({ value: transformed }), // transformed类型为number })
顺序调换后的异常调用
shapeAdapter({ original: { value: 1 }, revert: (transformed) => ({ value: transformed }), // transformed类型为unknown adapt: (original) => original.value, })
TypeScript版本:5.5.2
解决方案
问题本质是TypeScript按对象属性顺序进行类型推断,当revert先于adapt时,Transformed泛型参数尚未被adapt的返回值推断,因此默认设为unknown。我们可以通过调整泛型约束,让revert的参数类型直接依赖于adapt的返回值,消除顺序依赖。
修改后的函数定义
function shapeAdapter<Original, AdaptFn extends (original: Original) => unknown>(props: { original: Original; adapt: AdaptFn; revert: (transformed: ReturnType<AdaptFn>) => Original; }) { throw new Error("Implementation does not matter") }
原理
- 新增
AdaptFn泛型参数,约束为接收Original类型参数的函数 revert的参数类型直接使用ReturnType<AdaptFn>,即adapt的返回值类型- 无论
adapt和revert的顺序如何,TypeScript都会先从original推断Original,再从adapt推断AdaptFn,最终确定revert的参数类型
验证调换顺序的调用
shapeAdapter({ original: { value: 1 }, revert: (transformed) => ({ value: transformed }), // transformed类型正确推断为number adapt: (original) => original.value, })
可选方案:拆分参数
如果允许调整函数参数形式,将单个对象参数拆分为多个独立参数,也能避免顺序问题(TypeScript会按参数顺序依次推断类型):
function shapeAdapter<Original, Transformed>( original: Original, adapt: (original: Original) => Transformed, revert: (transformed: Transformed) => Original ) { throw new Error("Implementation does not matter") }
内容的提问来源于stack exchange,提问作者Gabriel Pureliani
相关产品推荐
相关产品推荐

