如何为动态函数参数实现TypeScript自动补全?
TypeScript类型安全调用对象方法的解决方案
场景与问题背景
定义了如下只读对象:
const obj = { property1: { func: ({num1,num2,operation}:{num1: number, num2: number, operation: string}) => "p1" }, property2: { func: ({obj}:{obj: {[key: string]: string}}) => "p2" } } as const
需求是实现一个函数,通过传入属性名(如property1),调用对应属性下的func方法。
初始不安全实现
最初的版本使用any类型,完全失去TypeScript的类型校验和自动补全能力:
function getFuncFromObj(property: string, parameters: {[key:string]: any}): any { return obj[property]['func'](parameters) } getFuncFromObj("property1", {num1: 2, num2: 5, operation: "+"})
泛型版本的问题
尝试泛型版本后,虽然能实现自动补全,但调用时TypeScript抛出类型错误:
function getFuncFromObj<T extends keyof typeof obj, K extends Parameters<typeof obj[T]["func"]>[0]>(key: T,parameters: K): string { return obj[key]["func"](parameters) } getFuncFromObj("property1", {num1: 2, num2:5, operation: "+"})
错误信息:
TS2345: Argument of type '{ num1: number; num2: number; operation: string; } | { obj: { [key: string]: string; }; }' is not assignable to parameter of type '{ num1: number; num2: number; operation: string; } & { obj: { [key: string]: string; }; }'. Type '{ num1: number; num2: number; operation: string; }' is not assignable to type '{ num1: number; num2: number; operation: string; } & { obj: { [key: string]: string; }; }'. Property 'obj' is missing in type '{ num1: number; num2: number; operation: string; }' but required in type '{ obj: { [key: string]: string; }; }'. 318 return obj[key]["func"](parameters) ~~~~~~~~~~
问题根源:TypeScript无法跟踪泛型参数T和K的关联关系,会将parameters推断为所有可能参数的联合类型,但函数调用时要求参数满足所有func的参数(即交叉类型),导致类型不匹配。
正确实现方案
方案1:单泛型参数关联类型
直接通过单个泛型参数T绑定属性名与对应func的参数类型,让TypeScript精确推断参数:
function getFuncFromObj<T extends keyof typeof obj>( key: T, parameters: Parameters<typeof obj[T]["func"]>[0] ): ReturnType<typeof obj[T]["func"]> { return obj[key].func(parameters) as ReturnType<typeof obj[T]["func"]>; }
方案2:预定义映射类型
先通过映射类型定义每个属性对应的参数类型,再在函数中使用:
// 预定义每个属性对应的func参数类型 type ObjFuncParams = { [K in keyof typeof obj]: Parameters<typeof obj[K]["func"]>[0]; }; function getFuncFromObj<T extends keyof ObjFuncParams>( key: T, parameters: ObjFuncParams[T] ): string { return obj[key].func(parameters); }
验证效果
两种方案都能实现:
- 自动补全属性名和对应参数
- 严格的类型校验,参数不匹配时直接报错
// 合法调用,自动补全正常 getFuncFromObj("property1", { num1: 2, num2: 5, operation: "+" }); getFuncFromObj("property2", { obj: { name: "test" } }); // 非法调用,TypeScript直接报错 getFuncFromObj("property1", { obj: {} }); // 参数不符合property1的要求 getFuncFromObj("property1", { num1: 2, operation: "+" }); // 缺少num2参数
内容的提问来源于stack exchange,提问作者Bash
相关产品推荐
相关产品推荐

