如何修复嵌套对象中函数参数的TypeScript类型约束错误?
如何修复嵌套对象中函数参数的TypeScript类型约束错误?
嘿,我来帮你搞定这个TypeScript类型问题!
你遇到的报错本质是:TypeScript没办法100%确定TApi[KEY][METHOD]一定是个可调用的函数——虽然我们肉眼能看到person和book下面的属性全是函数,但因为你用了as const把整个Api对象标记为只读,TypeScript在做类型推导时,会把这些属性的类型当成只读的函数类型,而Parameters这个工具类型要求输入必须严格符合(...args: any) => any的函数约束,所以就触发了类型不匹配的错误。
解决思路
我们需要给泛型METHOD加一个额外的约束,明确它只能是TApi[KEY]对象下对应值为函数的键名。这样TypeScript就能放心地把TApi[KEY][METHOD]当成函数来处理,Parameters工具类型也能正常提取参数类型了。
方案1:直接在泛型里加条件约束
修改你的executeApi函数泛型定义,给METHOD加上过滤条件:
const Api = { person: { find: (arg:{paramFind:string}) => {}, create: (arg:{paramCreate:string}) => {}, edit: (arg:{paramEdit:string}) => {}, remove: (arg:{paramRemove:string}) => {} }, book: { find: (arg:{paramFind:string}) => {}, create: (arg:{paramCreate:string}) => {}, edit: (arg:{paramEdit:string}) => {}, remove: (arg:{paramRemove:string}) => {} } } as const type TApi = typeof Api function executeApi< KEY extends keyof TApi, // 这里加了条件约束:只允许METHOD是TApi[KEY]下对应函数的键 METHOD extends keyof TApi[KEY] & (TApi[KEY][METHOD] extends (...args: any[]) => any ? METHOD : never) >( arg: { key: KEY, method: METHOD, // 现在Parameters能正常推导参数类型了 param: Parameters<TApi[KEY][METHOD]>[0] } ) { // 你的缓存逻辑代码 // 现在不需要as any断言了! return Api[arg.key][arg.method](arg.param) } // 测试调用完全正常,类型检查生效 executeApi({ key:'person', method: 'create', param: { paramCreate: 'John Doe' } }) executeApi({ key:'book', method: 'find', param: { paramFind: '1984' } })
方案2:用辅助类型提升可读性
如果觉得泛型里的条件约束太啰嗦,可以预先定义一个辅助类型,专门用来提取对象中值为函数的键名,后续还能复用:
const Api = { person: { find: (arg:{paramFind:string}) => {}, create: (arg:{paramCreate:string}) => {}, edit: (arg:{paramEdit:string}) => {}, remove: (arg:{paramRemove:string}) => {} }, book: { find: (arg:{paramFind:string}) => {}, create: (arg:{paramCreate:string}) => {}, edit: (arg:{paramEdit:string}) => {}, remove: (arg:{paramRemove:string}) => {} } } as const type TApi = typeof Api // 辅助类型:提取对象T中所有值为函数的键名 type FunctionKeys<T> = { [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never }[keyof T] function executeApi< KEY extends keyof TApi, METHOD extends FunctionKeys<TApi[KEY]> // 直接复用辅助类型 >( arg: { key: KEY, method: METHOD, param: Parameters<TApi[KEY][METHOD]>[0] } ) { // 缓存逻辑代码 return Api[arg.key][arg.method](arg.param) } // 测试调用正常 executeApi({ key:'person', method: 'create', param: { paramCreate: 'John Doe' } })
这两种方案都能解决你的参数类型约束问题,而且还能去掉之前的as any断言,让类型检查更严格。
内容来源于stack exchange
相关产品推荐
相关产品推荐

