我正在 TypeScript 中实现一个类型安全的
shapeAdapter
函数,它接受一个原始对象、一个用于转换它的 adapt
函数以及一个用于将其转换回来的 revert
函数。
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")
}
当
adapt
在 revert
之前声明时,该函数将按预期工作:
shapeAdapter({
original: { value: 1 },
adapt: (original) => original.value,
revert: (transformed) => ({ value: transformed }), // transformed is of type number as expected
})
但是,当我交换
adapt
和 revert
的顺序时,类型推断就会中断:
shapeAdapter({
original: { value: 1 },
revert: (transformed) => ({ value: transformed }), // "transformed" is of type unknown! should be number
adapt: (original) => original.value,
})
在第二个示例中,
transformed
函数中的revert
被推断为unknown
而不是number
。
我使用
NoInfer
实用程序类型来防止过度类型加宽,但它不能解决此问题。
有没有办法无论这些回调的顺序如何都保持正确的类型推断?
TypeScript 版本:
5.5.2
我尝试过的: 我最初在
adapt
之前使用 revert
实现了该函数,它按预期工作,但后来我尝试重新排序参数,将 revert
放在 adapt
之前,但它破坏了类型推断,然后我尝试使用NoInfer
通用参数上的实用程序类型可以防止过度类型扩展,但这也没有帮助。
我的期望: 我希望 TypeScript 能够根据
Original
函数的结构推断 Transformed
和 shapeAdapter
类型之间的关系,而不管回调的顺序如何。
请尝试改变
revert: (transformed: NoInfer<Transformed>) => NoInfer<Original>;
到
revert: (transformed: NoInfer<Transformed>) => Original;
有效的代码中发生了什么
shapeAdapter({
original: { value: 1 }, // Original is inferred as { value: number }
adapt: (original) => original.value, // Transformed is inferred as number
revert: (transformed) => ({ value: transformed }) // return value is inferred as Original
});
不起作用的代码中发生了什么
shapeAdapter({
original: { value: 1 }, // OK, as above
revert: (transformed) => ({ value: transformed }), // fails because of NoInfer on both Original and Transformed
adapt: (original) => original.value
})