如何为柯里化函数接收的回调参数正确标注TypeScript类型
解决柯里化Props Getter工厂的类型标注问题
问题背景
我正在尝试创建一个柯里化的props getter工厂函数:外层函数接收defaultParams和propsConstructor回调,propsConstructor负责结合defaultParams和内层函数后续传入的新props,计算出最终的props对象。
当前遇到的问题是:调用内层函数时,传入的props参数以及返回的对象类型都被错误标注为AnyObject,无法准确推导实际类型。
原代码示例
// basic types type EmptyObject = Record<string, never> type AnyObject = Record<string, unknown> type ObjectType = EmptyObject | AnyObject export type PropsConstructor< DefParams extends AnyObject, Props extends AnyObject, // 后续嵌套函数调用时接收的参数 ReturnObject extends AnyObject > = (defaultParams: DefParams, props: Props) => ReturnObject /** * @description input field props getter fabric * @returns props object that will be passed to input */ export const createPropsGetter = < DefParams extends AnyObject, ReturnObject extends AnyObject, Constr extends PropsConstructor<DefParams, AnyObject, ReturnObject> >({ defaultParams, propsConstructor, }: { defaultParams: DefParams propsConstructor: Constr }) => { return <NewProps extends AnyObject>(props: NewProps) => { return propsConstructor(defaultParams, props) } } const defaultParams = { one: 1, two: 2 } type Props = { four: number } type ReturnObject = typeof defaultParams & Props const propsConstructor: PropsConstructor< typeof defaultParams, { four: 4 }, ReturnObject > = (defParams, props) => ({ ...defParams, ...props }) // 类型被推导为:<{ four: number }>(props: { four: number }) => AnyObject const getter = createPropsGetter({ defaultParams, propsConstructor, }) const props = getter({ four: 4 }) props // 类型为AnyObject,不符合预期
解决方案
问题根源在于原代码中用AnyObject作为PropsConstructor的中间参数类型,导致TypeScript无法保留实际的类型信息。我们需要调整泛型参数的定义,让TS能准确推导内层函数的参数和返回值类型:
// basic types type EmptyObject = Record<string, never> type AnyObject = Record<string, unknown> type ObjectType = EmptyObject | AnyObject export type PropsConstructor< DefParams extends AnyObject, Props extends AnyObject, ReturnObject extends AnyObject > = (defaultParams: DefParams, props: Props) => ReturnObject /** * @description input field props getter fabric * @returns props object that will be passed to input */ export const createPropsGetter = < DefParams extends AnyObject, Props extends AnyObject, Return extends AnyObject >({ defaultParams, propsConstructor, }: { defaultParams: DefParams propsConstructor: PropsConstructor<DefParams, Props, Return> }) => { // 直接使用Props类型约束内层函数的参数,无需额外泛型 return (props: Props): Return => { return propsConstructor(defaultParams, props) } } const defaultParams = { one: 1, two: 2 } type Props = { four: number } type ReturnObject = typeof defaultParams & Props const propsConstructor: PropsConstructor< typeof defaultParams, Props, ReturnObject > = (defParams, props) => ({ ...defParams, ...props }) // 类型正确推导:(props: Props) => ReturnObject const getter = createPropsGetter({ defaultParams, propsConstructor, }) const props = getter({ four: 4 }) props // 类型为{ one: number; two: number; four: number },符合预期
关键调整说明
- 将
Props从Constr泛型的嵌套约束中抽离,作为createPropsGetter的独立泛型参数,让TypeScript能直接捕获内层函数需要接收的props类型 - 移除多余的
Constr泛型,直接用PropsConstructor<DefParams, Props, Return>约束propsConstructor参数,避免类型信息丢失 - 内层函数不再声明新的
NewProps泛型,直接复用Props类型,确保传入的参数与propsConstructor的要求一致,同时返回值类型也能准确推导为Return
内容的提问来源于stack exchange,提问作者Evgeniy Talko
相关产品推荐
相关产品推荐

