如何定义TypeScript类型将函数记录转换为重载函数签名?
TypeScript Trait函数类型定义解决方案
要实现Trait返回的函数能够精准匹配传入对象中每个方法的参数,同时对无效参数触发类型错误,可通过映射类型生成函数联合的方式解决:
核心类型定义
type TraitType<TS extends { [key: string]: (...args: any) => any }> = { [K in keyof TS]: (args: Parameters<TS[K]>[0]) => ReturnType<TS[K]> }[keyof TS];
完整实现代码
type TraitType<TS extends { [key: string]: (...args: any) => any }> = { [K in keyof TS]: (args: Parameters<TS[K]>[0]) => ReturnType<TS[K]> }[keyof TS]; function Trait<TS extends { [key: string]: (...args: any) => any }>(ts: TS): TraitType<TS> { // 实际逻辑需根据需求完善,此处仅作类型兼容的示例实现 return ((args: any) => { if ('left' in args && 'right' in args) return ts.Alt(args); if ('value' in args) return ts.Char(args); if ('first' in args && 'second' in args) return ts.Cat(args); throw new Error('Invalid argument structure'); }) as TraitType<TS>; } const printLang = Trait({ Alt: ({ left, right }: { left: string; right: string }) => `${left}|${right}`, Char: ({ value }: { value: string }) => `${value}`, Cat: ({ first, second }: { first: string; second: string }) => `${first},${second}` }); // 合法调用:匹配对应方法的参数签名 printLang({ left: 'foo', right: 'bar' }); printLang({ value: 'baz' }); printLang({ first: 'qux', second: 'quux' }); // 非法调用:触发类型错误 printLang({ error: '?' }); // 类型检查报错:对象字面量只能包含已知属性,'error' 不在允许的参数类型中
方案说明
TraitType通过映射类型遍历传入对象的每个方法键,为每个方法生成专属的函数类型(参数为方法的第一个入参,返回值为方法的返回类型)。- 最后通过
[keyof TS]将所有专属函数类型提取为联合类型,TypeScript在调用时会自动匹配联合中的有效签名,确保参数与对应方法严格匹配。
对比原问题的解决点
- 替代
TS[keyof TS]:避免仅取第一个函数定义的问题,保留所有方法的类型信息。 - 替代
(self: TS[keyof TS]) => ...:不再使用参数联合类型,而是为每个方法绑定专属参数,调用时能精准匹配。 - 替代
(...args: Parameters<TS[keyof TS]>) => ...:避免参数变成所有方法参数的交集,确保每个调用只需要符合某一个方法的参数结构。
内容的提问来源于stack exchange,提问作者mlhaufe
相关产品推荐
相关产品推荐

