TypeScript 中的多重继承

Migel Hewage Nimesha 2024年2月15日
  1. TypeScript 中的单一继承
  2. TypeScript 类的多重继承
  3. TypeScript 接口的多重继承
  4. TypeScript Mixins 的多重继承
TypeScript 中的多重继承

多年来已经发展了几种编程范式。面向对象编程(OOP)是基于现实世界实体及其交互的主要范式之一。

继承是众所周知的 OOP 概念之一,它允许子实体获取父实体的属性和行为。

TypeScript 中的单一继承

TypeScript 在某种程度上支持 OOP 技术。它支持从一个父实体继承,允许程序员有效地重用他们的代码。

我们可以使用 extends 关键字从父实体继承,如下所示。

class Animal {
    constructor() {
        console.log("Animal class");
    }
}

class Cat extends Animal {

    constructor() {
        super();
    }
}

const cat = new Cat();

输出:

"Animal class"

这称为单继承,给定的类只能扩展到一个父类。

TypeScript 类的多重继承

在类 Java 语言中,可以从多个父实体获取属性和行为。这称为多重继承。

TypeScript 不支持多重继承。

多重继承

让我们尝试使用 extends 在 TypeScript 中扩展多个父类。

class Engineer {
    constructor() {
        console.log("Employee class");
    }
}

class Person {
    constructor() {
        console.log("Person class");
    }
}

class Employee extends Engineer, Person {
}

然后,让我们转译 TypeScript 代码,如下所示。

tsc example1.ts

输出:

TypeScript 多重继承 - 输出 1

正如预期的那样,它给出了一个错误,即 TypeScript 只允许扩展单个类。

TypeScript 接口的多重继承

TypeScript 接口支持开箱即用的多重继承。它们可以扩展多个类。

让我们创建两个类,PersonEngineer,并添加一些虚拟方法。

class Person {
    name: string;

    constructor() {
       console.log("Person class");
    }

    sayImAPerson(){
        console.log("Hey, I am a person");
    }
}

class Engineer {
    salary: number;
    constructor() {
        console.log("Engineer class");
    }
    sayImAnEngineer(){
        console.log("I am an engineer too");
    }
}

接下来,我们将创建一个新类型或类来扩展上述两个类。

class Employee {
    empId: string;
}

由于 Employee 类不能扩展多个父类,我们应该使用同名 Employee 的接口来使用 TypeScript 声明合并。通过这种方式,你可以合并接口和类。

让我们创建 Employee 接口,它扩展了 PersonEngineer 类,如下所示。

interface Employee extends Person, Engineer {
}

让我们转译 TypeScript 代码并检查是否有任何错误。

输出:

TypeScript 多重继承 - 输出 2

正如预期的那样,在接口声明中使用具有多个父类的 extends 时没有错误。因此,接口支持多重继承。

但是如果我们在继承类内部调用一个方法,还是有问题的。我们无权访问方法实现。

让我们尝试调用 sayImAnEngineer() 方法。

let emp: Employee = new Employee;
emp.sayImAnEngineer();

我们应该先编译代码;它不会给出任何错误。然后,尝试运行生成的 JavaScript;它会引发错误,如以下输出所示。

输出:

TypeScript 多重继承 - 输出 3

TypeScript 找不到 sayImAnEngineer 方法。我们可以通过使用 TypeScript mixins 来克服这个问题。

TypeScript Mixins 的多重继承

TypeScript mixins 机制可以将父类中所有可用的方法复制到派生类或子类中。mixin 创建方法应该遍历父类中的所有属性并检索内容。

然后,它应该按原样设置派生类中的所有内容。TypeScript 官方文档提供了一个方法:【mixin 创建方法】。

建议在你的 TypeScript 文件中使用,如下所示。

function applyMixins(derivedCtor: any, constructors: any[]) {
  constructors.forEach((baseCtor) => {
    Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {
      Object.defineProperty(
        derivedCtor.prototype,
        name,
        Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
          Object.create(null)
      );
    });
  });
}

让我们在 TypeScript 示例中包含 applyMixins 方法。

class Person {
    name: string;

    constructor() {
       console.log("Person class");
    }

    sayImAPerson(){
        console.log("Hey, I am a person");
    }
}

class Engineer {
    salary: number;
    constructor() {
        console.log("Engineer class");
    }
    sayImAnEngineer(){
        console.log("I am an engineer too");
    }
}

class Employee {
    empId: string;
}

interface Employee extends Person, Engineer {

}

function applyMixins(derivedCtor: any, constructors: any[]) {
  constructors.forEach((baseCtor) => {
    Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {
      Object.defineProperty(
        derivedCtor.prototype,
        name,
        Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
          Object.create(null)
      );
    });
  });
}

现在,让我们调用 applyMixins 方法,如下所示。

applyMixins(Employee, [Person, Engineer]);

第一个参数应该是派生类;在这种情况下,它是 Employee 类。下一个参数是一个数组,其中包含派生类将扩展的所有父类。

最后,让我们创建一个 Employee 对象并从 Engineer 父类调用 sayImAnEngineer 方法。

let emp: Employee = new Employee;
emp.sayImAnEngineer();

输出:

TypeScript 多重继承 - 输出 4

这次没有错误;这意味着 mixins 技术有效。这样,你可以在 TypeScript 中实现多重继承。

Migel Hewage Nimesha avatar Migel Hewage Nimesha avatar

Nimesha is a Full-stack Software Engineer for more than five years, he loves technology, as technology has the power to solve our many problems within just a minute. He have been contributing to various projects over the last 5+ years and working with almost all the so-called 03 tiers(DB, M-Tier, and Client). Recently, he has started working with DevOps technologies such as Azure administration, Kubernetes, Terraform automation, and Bash scripting as well.