如何在TypeScript抽象类中实现返回子类构造参数的抽象方法?
TypeScript 抽象类 Entity 构造属性方法实现方案
需要在TypeScript中实现一个名为Entity的抽象类,其中包含一个抽象方法constructorProps(),该方法需返回子类构造所需的属性数组。
示例1:无自定义构造函数的子类
当子类没有自定义构造函数时,constructorProps()的返回类型应为空元组:
class Entity<Child extends Entity<any>> { abstract constructorProps(): // ??? 此处应填什么 ??? } class Foo extends Entity<Foo> { override constructorProps() { return [] } }
示例2:带参数构造函数的子类
当子类实现了接收参数的构造函数时,constructorProps()需返回对应参数类型的数组,比如Bar类接收string类型参数,返回类型应为[string]:
class Bar extends Entity<Bar> { name: string; constructor(name: string) { super(); // 注意:子类自定义构造函数必须调用super() this.name = name; } override constructorProps() { return [this.name]; } }
思路与疑问
我已有初步思路——将子类作为类型参数传入抽象类,让Entity能够引用子类类型,但不清楚具体实现方式。
疑问:
- 是否可以从实例类型(如
ConstructorOf<Bar>)中获取构造函数的参数类型? - 当前的实现思路是否正确?有没有其他实现方式?
问题解答
疑问1:可以通过内置类型工具获取构造函数参数类型
TypeScript内置了ConstructorParameters工具类型,它能从构造函数类型中提取参数类型组成的元组。注意该工具接收的是构造函数类型而非实例类型,可通过typeof操作符从类本身获取构造函数类型:
// 从Bar类获取构造函数参数类型 type BarConstructorParams = ConstructorParameters<typeof Bar>; // 类型为 [string]
疑问2:你的思路可行,以下是具体实现方案
通过子类类型参数传递+ConstructorParameters工具类型,可自动约束constructorProps()的返回类型,无需手动指定。
完整实现代码
// 抽象类Entity,通过类型参数Child引用子类 abstract class Entity<Child extends Entity<any>> { // 利用ConstructorParameters自动推导子类构造函数的参数元组类型 abstract constructorProps(): ConstructorParameters<typeof Child>; } // 无自定义构造函数的子类Foo class Foo extends Entity<Foo> { override constructorProps() { return []; // 符合空元组类型要求 } } // 带参数构造函数的子类Bar class Bar extends Entity<Bar> { name: string; constructor(name: string) { super(); this.name = name; } override constructorProps() { return [this.name]; // 符合[string]类型要求 } } // 测试:返回类型不匹配时会触发TypeScript报错 class Baz extends Entity<Baz> { age: number; constructor(age: number, name: string) { super(); this.age = age; } override constructorProps() { // 错误:类型 '[number]' 不能赋值给类型 '[number, string]' // return [this.age]; return [this.age, "test"]; // 正确 } }
其他实现思路
如果不想通过子类类型参数传递,也可以直接用泛型约束指定构造参数元组,但这种方式需要子类手动声明参数类型,无法自动推导,实用性稍弱:
abstract class Entity<T extends any[] = []> { abstract constructorProps(): T; } class Foo extends Entity<[]> { override constructorProps() { return []; } } class Bar extends Entity<[string]> { name: string; constructor(name: string) { super(); this.name = name; } override constructorProps() { return [this.name]; } }
内容的提问来源于stack exchange,提问作者Kevin Chavez
相关产品推荐
相关产品推荐

