TypeScript - Mixins



TypeScript 是一种面向对象的编程语言,包含类,它是对象的蓝图。类可以在 TypeScript 中定义如下。

class MathOps {
    // defining a method
    add(a: number, b: number): void {
        console.log('sum is: ', a + b);
    }
}

现在,假设我们有多个像上面这样的类,它们包含不同的操作。

如果您想重用这两个类并希望通过扩展这两个类来创建一个第三个类,该怎么办?例如,如果您尝试使用 'MathOps1' 和 'BitwiseOps' 类扩展 'allOps' 类,TypeScript 会给您一个错误,因为 TypeScript 不允许多重继承。

class allOps extends MathOps, BitwiseOps {
    // Executable code
}

为了解决上述问题,开发人员可以在 TypeScript 中使用 mixins。

Mixins 简介

在 TypeScript 中,mixins 是一种允许我们通过多个类扩展单个类的概念。这样,我们可以重用类组件,并在单个类中组合它们的方法和属性。

我们可以使用声明合并技术通过多个类扩展单个类。

声明合并

当您有两个相同名称的声明时,它将被合并而不会抛出任何错误。

例如,在下面的代码中,我们两次定义了接口 'A',其中包含不同的属性。之后,我们创建了类型为 'A' 的 'obj' 对象,其中包含属性 'a' 和 'b',因为这两个接口 'A' 已合并。

// Definition of an interface with the same name twice
interface A {
    a: string;
}

interface A {
    b: string;
}

// Object that implements the interface
let obj: A = {
    a: 'a',
    b: 'b'
};

console.log(obj.a); // a
console.log(obj.b); // b

编译后,它将生成以下 TypeScript 代码。

// Object that implements the interface
let obj = {
    a: 'a',
    b: 'b'
};
console.log(obj.a); // a
console.log(obj.b); // b

输出

上面示例的输出如下:

a
b

现在,让我们了解如何使用声明合并技术将多个类与单个类扩展。

实现我们的 Mixin 辅助函数

让我们逐行了解下面的示例代码。

  • 我们定义了 'swimmer' 类,它包含 StartSwim() 和 EndSwim() 方法。

  • 接下来,我们定义了 Cyclist 类,它包含 startCycle() 和 endCycle() 方法。

  • 接下来,'combineMixins()' 函数是一个辅助函数,允许我们将两个或多个类的属性和方法混合到一个类中。这就是为什么它被称为 mixin 函数。

    • 该函数将派生类或父类作为第一个参数,并将基类或子类的数组作为第二个参数。

    • 它使用 forEach() 方法遍历基类的数组。

    • 在 forEach() 方法回调中,它遍历单个基类的每个属性,并使用 defineProperty() 方法将其添加到派生类的原型中。

  • 之后,我们定义了 'Biathlete' 类。

  • 接口 'Biathlete' 扩展了 'Swimmer' 和 'Cyclist' 类,以将这两个类的所有属性和方法声明合并到 'Biathlete' 类中。但是,它不会合并方法的实现。

  • 接下来,我们调用 'combineMixins()' 函数,该函数将其他类中类的实现合并。

  • 接下来,我们创建了 'Biathlete' 类的实例,并使用它来调用 'Swimmer' 和 'Cyclist' 类的 方法。

// Swimmer class definition
class Swimmer {
    // Methods
    StartSwim() {
        console.log('Starting the swimming session...');
    }
    EndSwim() {
        console.log('Completed the swimming session.');
    }
}

//   Cyclist class definition
class Cyclist {
    // Methods
    StartCycle() {
        console.log('Starting the cycling session...');
    }
    EndCycle() {
        console.log('Completed the cycling session.');
    }
}

// export class Biathlete extends Swimmer, Cyclist{}
function combineMixins(derived: any, bases: any[]) {
    // Iterate over the base classes
    bases.forEach(base => {
        // Iterate over the properties of the base class
        Object.getOwnPropertyNames(base.prototype).forEach(name => {
            // Copy the properties of the base class to the derived class
            Object.defineProperty(derived.prototype, name, Object.getOwnPropertyDescriptor(base.prototype, name));
        });
    });
}

// Export Biathlete class
export class Biathlete { }
// Use interface to combine mixins
export interface Biathlete extends Swimmer, Cyclist { }
// Combine mixins
combineMixins(Biathlete, [Swimmer, Cyclist]);

// Create an instance of Biathlete class
const athlete = new Biathlete();
// Call the methods
athlete.StartSwim();
athlete.EndSwim();
athlete.StartCycle();
athlete.EndCycle();

输出

Starting the swimming session...
Completed the swimming session.
Starting the cycling session...
Completed the cycling session.

这样,我们可以使用接口合并两个组件的结构。之后,我们可以使用 mixins 函数将两个组件的实现组合到第三个组件中并重用它们。

广告