You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用泛型扩展函数对象?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的函数签名是两个重载的组合:
    1. (a: 'a'): 'a'
    2. (...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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 05:22:34