TypeScript子类如何覆写父类泛型方法并缩小参数类型?
问题背景
现有TypeScript父类定义:
class FooClass { getFoo<FooType extends string | number>(foo: FooType): string { throw "not implemented"; } }
尝试创建两个子类继承该父类,写法如下:
class NumberFooClass extends FooClass { getFoo(foo: number): string { return "" + foo; } } class StringFooClass extends FooClass { getFoo(foo: string): string { return foo; } }
但两个子类均触发TypeScript错误,以NumberFooClass为例,报错信息如下:
Property 'getFoo' in type 'NumberFooClass' is not assignable to the same property in base type 'FooClass'.
Type '(foo: number) => string' is not assignable to type '<FooType extends string | number>(foo: FooType) => string'.
Types of parameters 'foo' and 'foo' are incompatible.
Type 'FooType' is not assignable to type 'number'.
Type 'string | number' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.ts(2416)
尝试修改写法为:
class NumberFooClass extends FooClass { getFoo<number>(foo: number): string { return "" + foo; } }
依然报错:
'number' is declared but its value is never read.ts(6133)
Type parameter name cannot be 'number'.
解决方案
问题核心在于父类的泛型是方法级泛型,它要求子类的getFoo方法必须能接受父类泛型约束的所有类型(string | number),子类缩小参数类型后违反了这个兼容性要求。正确的做法是把泛型从方法级别提升到类级别,让父类本身成为泛型类,子类通过指定具体泛型参数来缩小类型范围:
1. 重构父类为泛型类
class FooClass<T extends string | number> { getFoo(foo: T): string { throw "not implemented"; } }
2. 创建子类时指定具体泛型类型
class NumberFooClass extends FooClass<number> { getFoo(foo: number): string { return "" + foo; } } class StringFooClass extends FooClass<string> { getFoo(foo: string): string { return foo; } }
这样写法完全符合TypeScript的类型约束,子类可以正确缩小参数类型,同时满足继承的类型兼容性要求。
原写法失败原因
父类的方法泛型FooType extends string | number意味着:任何调用getFoo的地方都可以传入string或number类型参数,子类必须保证这一点。而你的子类只接受单一类型,违反了这个约定,因此触发报错。
将泛型移到类级别后,父类的泛型参数T会被子类固定为具体类型,此时getFoo的参数类型也被固定,子类的实现就完全符合类型要求了。
内容的提问来源于stack exchange,提问作者C_Z_

