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 函式將兩個元件的實現組合到第三個元件中並重用它們。

廣告