TypeScript如何移除函数对象字面量首个参数并保留类型?
TypeScript实现移除对象中所有函数首个参数并保留类型信息
需求说明
需要编写函数doSomething,接收一个值T和一个由函数组成的对象字面量:
- 每个输入函数的首个参数固定为
Proxy<T>类型 - 返回结构完全一致的对象,但每个函数移除首个参数
- 必须完整保留剩余参数和返回值的类型信息,避免参数退化为
unknown[]
预期效果:
const res = doSomething('someVal', { func1: (proxy, other: string) => proxy.value + other }); res.func1('other string'); // 参数`other`被正确推断为string类型,返回值为string类型
问题分析
之前的尝试因类型定义过于嵌套复杂,导致要么返回函数参数变为unknown[],要么出现Target signature provides too few arguments编译错误,核心原因是泛型约束和类型推断逻辑不够直接。
解决方案
核心类型定义
首先定义一个通用类型,用于移除函数的首个参数:
type Proxy<T> = { value: T; }; // 移除函数的首个参数,保留剩余参数和返回值类型 type OmitFirstParam<F> = F extends (first: any, ...rest: infer P) => infer R ? (...rest: P) => R : never;
函数实现
直接通过泛型约束输入对象,并映射返回类型:
function doSomething<T, M extends Record<string, (proxy: Proxy<T>, ...args: any[]) => any>>( value: T, methods: M ): { [K in keyof M]: OmitFirstParam<M[K]> } { // 实际逻辑:为每个方法绑定Proxy实例,此处用类型断言跳过实现细节 return Object.fromEntries( Object.entries(methods).map(([key, fn]) => [ key, (...args: any[]) => fn({ value }, ...args) ]) ) as { [K in keyof M]: OmitFirstParam<M[K]> }; }
测试验证
// 调用示例,无编译错误 const res = doSomething('test', { help: (proxy: Proxy<string>, a: number) => `${proxy.value}${a}`, greet: (proxy: Proxy<string>, name: string) => `Hello ${name}, my value is ${proxy.value}` }); // 类型推断正确:res.help接收number参数,返回string res.help(123); // res.greet接收string参数,返回string res.greet("Alice");
解释
OmitFirstParam通过条件类型+infer直接提取函数的剩余参数和返回值,逻辑简洁且类型推断可靠- 泛型约束
M extends Record<string, (proxy: Proxy<T>, ...args: any[]) => any>确保输入对象的每个函数都符合“首个参数为Proxy<T>”的要求 - 返回类型通过映射类型
{ [K in keyof M]: OmitFirstParam<M[K]> }直接将每个输入函数转换为移除首个参数后的版本,完全保留类型信息
内容的提问来源于stack exchange,提问作者Daniel Gimenez
相关产品推荐
相关产品推荐

