TypeScript动态类型问题:execFunction调用类型不匹配报错求助
问题描述
我编写了以下TypeScript代码,定义了包含两个函数的对象,并实现了一个execFunction方法来根据指定key执行对应函数:
const obj = { func1: ({ a }: { a: string }) => { console.log(a) }, func2: ({ b }: { b: number }) => { console.log(b) }, } function execFunction<Key extends keyof typeof obj>(key: Key, params: Parameters<typeof obj[Key]>[0]) { const func: typeof obj[Key] = obj[key] return func(params) } execFunction('func1', { a: 'a' }) execFunction('func2', { b: 1 })
调用execFunction时自动补全功能正常,但执行func(params)时出现类型错误:
Argument of type '{ a: string; } | { b: number; }' is not assignable to parameter of type '{ a: string; } & { b: number; }'. Type '{ a: string; }' is not assignable to type '{ a: string; } & { b: number; }'. Property 'b' is missing in type '{ a: string; }' but required in type '{ b: number; }'.(2345)
尝试进行类型推断但未找到可行方案,寻求解决办法。
原因分析
这是TypeScript的典型类型推断限制:当泛型参数Key为keyof typeof obj的联合类型时,typeof obj[Key]会被推断为函数的联合类型,而Parameters<typeof obj[Key]>[0]是参数的联合类型。但TypeScript规定,调用函数联合类型时,传入的参数必须满足联合类型中所有函数的参数要求(即参数的交叉类型),这就导致了类型不匹配——你的params是{a:string} | {b:number},但联合函数要求的是同时包含a和b的交叉类型,因此报错。
虽然外部调用时,泛型实例化能正确关联key与params的类型,但函数内部的类型推断无法做到这种精准关联。
解决方案
方案1:类型断言快速绕过检查
通过类型断言明确告知TypeScript,params是当前函数的合法参数:
function execFunction<Key extends keyof typeof obj>(key: Key, params: Parameters<typeof obj[Key]>[0]) { const func = obj[key] return func(params as Parameters<typeof obj[Key]>[0]) }
方案2:用映射类型明确关联关系
定义映射类型让TypeScript清晰识别每个key对应的参数类型:
type FuncMap = typeof obj; type FuncParams<K extends keyof FuncMap> = Parameters<FuncMap[K]>[0]; function execFunction<K extends keyof FuncMap>(key: K, params: FuncParams<K>) { (obj[key] as (p: FuncParams<K>) => void)(params); }
方案3:元组类型优雅关联参数
将key和params打包成元组,利用TypeScript元组推断自动关联两者类型:
function execFunction<T extends [keyof typeof obj, any]>( ...args: T extends [infer K, Parameters<typeof obj[K]>[0]] ? T : never ) { const [key, params] = args; return obj[key](params); }
方案4:类型守卫严谨校验
适合参数类型复杂的场景,通过类型守卫确保params与key匹配:
function isFunc1Params(params: unknown): params is Parameters<typeof obj['func1']>[0] { return typeof params === 'object' && params !== null && 'a' in params; } function isFunc2Params(params: unknown): params is Parameters<typeof obj['func2']>[0] { return typeof params === 'object' && params !== null && 'b' in params; } function execFunction<Key extends keyof typeof obj>(key: Key, params: Parameters<typeof obj[Key]>[0]) { const func = obj[key]; if (key === 'func1' && isFunc1Params(params)) { return func(params); } else if (key === 'func2' && isFunc2Params(params)) { return func(params); } }
内容的提问来源于stack exchange,提问作者Je.
相关产品推荐
相关产品推荐

