如何在 TypeScript 的派生类中进行构造函数重载?

Posted

技术标签:

【中文标题】如何在 TypeScript 的派生类中进行构造函数重载?【英文标题】:How can I do constructor overloading in a derived class in TypeScript? 【发布时间】:2014-11-27 02:26:23 【问题描述】:

假设我有一个这样的“基础”类:

class CcDefinition 
  // Some properties here

  constructor (json: string);
  constructor (someVar: number, someOtherVar: string);
  constructor (jsonOrSomeVar: any, someOtherVar?: string) 
    if (typeof jsonOrSomeVar=== "string") 
      // some JSON wrangling code here
     else 
      // assign someVar and someOtherVar to the properties
    
  

我希望能够扩展这个基类,同时仍然支持构造函数重载。例如:

class CcDerived extends CcDefinition 
  // Some additional properties here

  constructor (json: string);
  constructor (someVar: boolean, someOtherVar: number, someAdditionalVar: string);
  constructor (jsonOrSomeVar: any, someOtherVar?: number, someAdditionalVar?: string) 
    if (typeof jsonOrSomeVar=== "string") 
      super.constructFromJson(jsonOrSomeVar);
     else 
      super.constructFromDef(someOtherVar, someAdditionalVar);
      // assign someVar to the additional properties of this derived class
    
  

问题在于 Typescript 要求“super”关键字在构造函数实现中首先出现(字面意思)。具体构建错误信息为:

“当类包含初始化属性或具有参数属性时,'super'调用必须是构造函数中的第一条语句。”

但是,我需要根据提供给扩展(派生)类的内容来确定将哪些参数传递给“超级”(即使用不同的构造函数重载)。您应该在这里假设派生类的构造函数重载可能与超级类的重载非常不同。

对于我想要实现的目标有解决方法吗?

【问题讨论】:

有人提出同样的问题(没有解决方案):[typescript.codeplex.com/workitem/91] 【参考方案1】:

此限制仅适用于您在派生类中有 已初始化 成员属性的情况,因此第一个解决方法是仅声明这些属性,然后在派生类中初始化它们类构造函数。

换句话说,你可以改变:

class CcDerived extends CcDefinition 
  y = 10;

  constructor (json: string);
  constructor (someVar: boolean, someOtherVar: number, someAdditionalVar: string);
  constructor (jsonOrSomeVar: any, someOtherVar?: number, someAdditionalVar?: string) 
    if (typeof jsonOrSomeVar=== "string") 
      super(jsonOrSomeVar);
     else 
      super(someOtherVar, someAdditionalVar);
    
  

到这里:

class CcDerived extends CcDefinition 
  // Some additional properties here
  y: number;

  constructor (json: string);
  constructor (someVar: boolean, someOtherVar: number, someAdditionalVar: string);
  constructor (jsonOrSomeVar: any, someOtherVar?: number, someAdditionalVar?: string) 
    this.y = 10;
    if (typeof jsonOrSomeVar=== "string") 
      super(jsonOrSomeVar);
     else 
      super(someOtherVar, someAdditionalVar);
    
  

注意这里的初始化顺序与其他OOP语言中的初始化顺序大致相同,需要注意不要从构造函数等调用虚方法。

如果这太令人反感,请注意限制只是第一个语句是一个超级调用。您通常可以重构超级调用:

class CcDerived extends CcDefinition 
  constructor (json: string);
  constructor (someVar: boolean, someOtherVar: number, someAdditionalVar: string);
  constructor (jsonOrSomeVar: any, someOtherVar?: number, someAdditionalVar?: string) 
      super(
          typeof jsonOrSomeVar === 'string' ? jsonOrSomeVar : someOtherVar,
          typeof jsonOrSomeVar === 'string' ? undefined : someAdditionalVar); 
  

不是最漂亮的,但至少在语义上是等价的。这确实假设您的基类构造函数正在检查 undefined(而不是 arguments.length)以确定调用了哪个重载。

【讨论】:

感谢 Ryan,我自己已经找到了“丑陋”的版本。我也会探讨您的第一个建议,但我的实际课程可能有点过于复杂而无法实际使用它。 我的代码无法使用第一个版本。我会继续这样做 - 但它仍然会报告原始错误。即使基类和派生类都在构造函数中初始化它们的成员。

以上是关于如何在 TypeScript 的派生类中进行构造函数重载?的主要内容,如果未能解决你的问题,请参考以下文章

C++如何使用派生类构造函数销毁基类中的对象

C ++:如何在派生类中定义基类构造函数,如果基构造函数具有带有私有成员的初始化列表[重复]

在 TypeScript 中为具有类型变量的抽象类中的派生类分配泛型类型

Typescript派生类和抽象类

派生类中的构造函数

如何在 Typescript 中用静态变量表达构造函数?