如何用泛型扩展函数对象?TypeScript类型定义疑问
TypeScript类型定义问题:让Bar继承Foo且ReturnType返回'a'
我们需要定义一组类型,满足两个核心要求:
Bar继承自Foo- 当
Bar传入泛型'a'得到BarA后,ReturnType<BarA>的结果为'a'
原代码及问题表现
interface Foo { (...args: any): any b: string } interface Bar<T extends string> extends Foo { (a: T): T b: T } // 预期BarA的类型结构: // { // (a:'a'):'a' // b: 'a' // } type BarA = Bar<'a'> type FooBarWorks = BarA['b'] // 结果符合预期:'a' type FooBar = ReturnType<BarA> // 实际结果:any,不符合预期的'a'
原接口方案失效的原因
当接口通过extends继承另一个接口时,函数签名会以重载的形式合并,而非覆盖。
具体到原代码:
Foo的函数签名是(...args: any): any,属于可以接受任意参数、返回任意类型的宽泛签名Bar<T>继承Foo后,自身的(a: T): T签名会和父接口的签名合并,最终BarA的函数签名是两个重载的组合:(a: 'a'): 'a'(...args: any): any
而TypeScript的ReturnType工具类型在处理重载函数时,只会取最后一个重载签名的返回值,也就是any,因此最终结果不符合预期。
可行解决方案及原理
使用条件类型的方式定义Bar<T>可以解决问题:
type Bar<T extends string> = { (a: T): T b: T } extends infer O extends Foo ? O : never
这个方案生效的核心逻辑:
这里并没有直接做接口继承,而是先创建包含目标函数签名和属性的类型,再通过infer O extends Foo让TypeScript验证该类型是否兼容于Foo,并推导兼容后的最终类型O。
在这个过程中,TypeScript不会保留重载签名,而是将原类型的函数签名(a: T): T视为Foo函数签名的子类型((a: T): T可以赋值给(...args: any): any),最终推导出来的O类型中,函数签名就是(a: T): T,而非重载组合。因此ReturnType<BarA>就能正确取到'a'。
内容的提问来源于stack exchange,提问作者TrevTheDev
相关产品推荐
相关产品推荐

