如何在含泛型的TypeScript类中重写方法并定义不同参数类型
TypeScript类中重写泛型方法并定义不同参数类型的解决方案
问题背景
能不能在TypeScript类里重写方法,同时用泛型定义不同的参数类型?我想靠这个创建灵活的抽象基类,还让子类有严格的类型校验。我怀疑这又是“关联联合类型”的问题,但用接口的话TypeScript应该有足够信息避免报错。
下面的代码在TypeScript v4.6.3里,类B重写doSomething方法时会触发如下错误:
TS2416: Property 'doSomething' in type 'B' is not assignable to the same property in base type 'A'. Type '(opts: BOpts) => void' is not assignable to type '<T extends AOpts>(opts: T) => void'. Types of parameters 'opts' and 'opts' are incompatible. Type 'T' is not assignable to type 'BOpts'. Property 'bar' is missing in type 'AOpts' but required in type 'BOpts'.
对应的代码:
interface AOpts { foo: number; } class A { public doSomething<T extends AOpts>(opts: T) { console.log(opts.foo); } } interface BOpts extends AOpts { bar: number; } class B extends A { // this line errors public override doSomething(opts: BOpts) { super.doSomething(opts); console.log(opts.bar); } }
问题原因
基类A的doSomething是泛型方法,它要求能接受所有继承自AOpts的类型作为参数。但子类B的重写方法只接受BOpts类型,这违反了里氏替换原则——父类的方法可以处理任意AOpts子类,而子类的方法却做不到,TypeScript自然会判定类型不兼容。
解决方案
要实现基类灵活、子类严格的需求,把泛型定义在类级别而非方法级别是最直接的方案:
interface AOpts { foo: number; } // 泛型定义在类上,约束整个类的参数类型,默认值设为AOpts保持兼容性 class A<T extends AOpts = AOpts> { public doSomething(opts: T) { console.log(opts.foo); } } interface BOpts extends AOpts { bar: number; } // 子类继承时指定具体的泛型类型BOpts class B extends A<BOpts> { public override doSomething(opts: BOpts) { super.doSomething(opts); console.log(opts.bar); } }
方案解释
- 类级泛型让基类A可以根据不同子类适配对应的参数类型,不再要求单个方法兼容所有可能的
AOpts子类。 - 子类B继承时明确指定
BOpts作为泛型参数,此时doSomething的参数类型被固定为BOpts,重写时类型完全匹配,不会触发报错。 - 这种方式既保留了基类的灵活性(可以适配任意
AOpts子类),又给子类提供了严格的类型校验,完美契合需求。
如果不想用类级泛型,也可以通过抽象类结合方法重载实现,但类级泛型的写法更简洁直观。
内容的提问来源于stack exchange,提问作者baseten
相关产品推荐
相关产品推荐

