TypeScript中为何无法推断泛型父类Closure的类型参数?
问题原因分析
当你定义非泛型类 B 继承自泛型父类 Closure<A> 时,TypeScript 并不会将父类的泛型参数信息保留在子类的类型元数据中。虽然 B 的实例确实是 Closure<A> 的子类型,但在条件类型 T extends Closure<infer U> 的匹配过程中,TypeScript 无法从具体子类 B 的类型信息中回溯推断出父类的泛型参数 A,最终只能返回默认的 unknown。
而 BaseOf<Closure<A>> 能正确得到 A,是因为 Closure<A> 是显式的泛型实例类型,直接携带了 Base 参数的完整类型信息,没有经过子类的类型擦除。
解决方案
方案一:在父类中添加类型标记属性
在 Closure 类中添加一个仅用于类型推断的虚拟属性,显式存储 Base 类型,让子类继承后保留该类型信息:
abstract class Closure<Base> { // 虚拟属性,仅用于类型标记,无需实现 readonly __baseType!: Base; } interface A { foo(args: { one: string, two: number }): void } class B extends Closure<A> implements A { foo(args: { one: string, two: number }) { } } type BaseOf<T extends Closure<unknown>> = T['__baseType']; type b = BaseOf<B>; // 现在得到 A 类型
方案二:将子类定义为泛型类
如果允许子类是泛型的,可以显式绑定 Base 参数,保留泛型信息:
abstract class Closure<Base> { } interface A { foo(args: { one: string, two: number }): void } // 显式将 Base 作为泛型参数,默认值设为 A class B<Base = A> extends Closure<Base> implements A { foo(args: { one: string, two: number }) { } } type BaseOf<T extends Closure<unknown>> = T extends Closure<infer U> ? U : never; type b = BaseOf<B>; // 得到 A 类型
方案三:从构造函数的实例类型推断
如果传入的是类的构造函数类型(比如 typeof B),可以调整 BaseOf 直接从实例类型推断:
abstract class Closure<Base> { } interface A { foo(args: { one: string, two: number }): void } class B extends Closure<A> implements A { foo(args: { one: string, two: number }) { } } type BaseOf<T> = InstanceType<T> extends Closure<infer U> ? U : never; type b = BaseOf<typeof B>; // 得到 A 类型
内容的提问来源于stack exchange,提问作者Sebastian Nemeth
相关产品推荐
相关产品推荐

