TypeScript中预填充首参的partial函数如何正确标注类型
问题描述
假设我有一个partial()函数,该函数接收一个可调用对象以及需要传入它的若干参数,功能是预填充该可调用对象的第一个参数。请问应当如何为该函数的参数添加类型标注,才能保证无论传入什么可调用对象,类型检查都可以正常工作?
初始无类型代码
function foo(a: string, b: number, c: string) { console.log('foo', a, b, c) } function bar(a: string) { console.log('bar', a) } function partial(callable, ...args) { callable('identity', ...args) }
无效的尝试方案
以下是我之前尝试的实现,但无法正常通过类型校验:
partial<T>(callable: (...args: [string, ...T[]]) => void, ...args: T[]) { callable('partial a', ...args); }
这个写法的核心问题是将剩余参数的类型统一推断为T[]数组类型,丢失了每个参数位置的独立类型信息,也无法校验参数数量是否匹配,比如传入foo时,要求第二个参数是number、第三个是string,这个写法无法约束传入的剩余参数和原函数参数一一对应。
正确类型标注实现
核心思路是用泛型捕获传入函数的完整类型,通过infer关键字推导原函数第一个固定为string的参数之后的剩余参数元组类型,将其作为partial函数接收的剩余参数类型,即可实现完整的类型校验:
// 独立函数版本 function partial<F extends (first: string, ...rest: any[]) => any>( callable: F, ...args: F extends (first: string, ...rest: infer R) => any ? R : never ) { callable('identity', ...args); } // 类方法版本(和类内定义格式对齐) class YourClass { partial<F extends (first: string, ...rest: any[]) => void>( callable: F, ...args: F extends (first: string, ...rest: infer R) => void ? R : never ) { callable('partial a', ...args); } }
类型校验效果
- 调用
partial(bar)时无需传入额外参数,类型检查正常通过 - 调用
partial(foo, 123, 'test')时,传入的剩余参数和foo第一个参数之后的b: number, c: string类型完全匹配,类型检查通过 - 如果调用
partial(foo, 'wrong', 'test'),第二个参数传入字符串而非要求的数字类型,TS会直接抛出类型错误 - 如果调用
partial(foo, 123)缺少第三个要求的字符串类型参数,TS也会报参数数量不匹配的错误 - 如果传入的可调用对象第一个参数不是
string类型,TS同样会抛出类型错误,符合预填充值为字符串的场景要求
内容的提问来源于stack exchange,提问作者Leonardo
相关产品推荐
相关产品推荐

