TypeScript中如何为带不同/额外参数的函数分配类型
TypeScript动态回调参数兼容方案
问题背景
需要实现通用函数evaluate_two,支持传入带不同额外参数的回调函数(如callback1/callback2/callback3),同时满足:
- 无需硬编码联合类型,动态适配回调的参数结构
- 调用时自动校验参数缺失(如
evaluate_two(tesstobj, 'one', callback2)需提示缺少min参数) - 自动校验参数类型(如传入错误类型时提示不匹配)
当前实现出现类型不兼容错误:
Argument of type '(key: string, value: unknown, min: number, max?: number) => number' is not assignable to parameter of type '(key: string, val: unknown, ...args: unknown[]) => number'. Types of parameters 'min' and 'args' are incompatible. Type 'unknown' is not assignable to type 'number'.
解决方案
通过泛型提取回调的剩余参数类型,将回调函数的参数拆分为固定前两个参数(key和val)与动态剩余参数Args,并约束函数的可变参数必须匹配Args类型,实现完全动态的参数适配。
核心修改代码
const evaluate_two = < O extends Obj, Args extends unknown[], R >(obj: O, prop: keyof O, vfunc: (key: string, val: unknown, ...args: Args) => R, ...args: Args) => { if (typeof prop !== 'string') throw new Error('error') return vfunc(prop, obj[prop], ...args) }
完整验证代码
// callbacks const callback1 = (key: string, value: unknown) => { if (typeof value !== 'number' || Number.isNaN(value)) throw new Error('error ' + key) return value } const callback2 = (key: string, value: unknown, min: number, max: number = Infinity) => { if (typeof value !== 'number' || Number.isNaN(value)) throw new Error('error ' + key) if (value < min || value > max) throw new Error('error') return value } const callback3 = (key: string, value: unknown, something: number) => { if (typeof value !== 'number' || Number.isNaN(value)) throw new Error('error ' + key) if (value === something) throw new Error('error') return value } type Obj = { [P: string]: unknown } const tesstobj: Record<string, unknown> = { one: 1, two: 'two' } // 原单参数回调函数 const evaluate = < O extends Obj, F extends (key: string, val: unknown) => ReturnType<F> >(obj: O, prop: keyof O, vfunc: F) => { if (typeof prop !== 'string') throw new Error('error') return vfunc(prop, obj[prop]) } // 改进后的多参数回调函数 const evaluate_two = < O extends Obj, Args extends unknown[], R >(obj: O, prop: keyof O, vfunc: (key: string, val: unknown, ...args: Args) => R, ...args: Args) => { if (typeof prop !== 'string') throw new Error('error') return vfunc(prop, obj[prop], ...args) } // 原函数验证 evaluate(tesstobj, 'one', callback1) // 正常执行 evaluate(tesstobj, 'one', callback2) // 预期报错:回调参数不匹配 // 新函数验证 evaluate_two(tesstobj, 'one', callback2) // 提示缺少min参数 evaluate_two(tesstobj, 'one', callback2, 1) // 正常执行(max为可选参数) evaluate_two(tesstobj, 'one', callback2, 1, 10) // 正常执行 evaluate_two(tesstobj, 'one', callback3, 'wrong') // 提示类型不匹配:string不能赋值给number evaluate_two(tesstobj, 'one', callback3, 1) // 正常执行
效果说明
- 调用
evaluate_two时,TypeScript会自动根据传入的回调函数推导所需额外参数,缺失时给出明确提示 - 参数类型不匹配时,立即触发类型错误提示
- 完全动态适配任意结构的回调函数,无需维护联合类型
内容的提问来源于stack exchange,提问作者bogdanoff
相关产品推荐
相关产品推荐

