Ostatnio rozpocząłem przygodę z językiem TypeScript. Wśród zalet odróżniających go od swojego przodka (języka JavaScript) jest silne typowanie i dużo bardziej intuicyjna obiektowość. Jednym z ograniczeń jest pojedyncze dziedziczenie (przypadłość wielu języków programowania). Na szczęście istnieje sposób na obejście tego problemu.

Załóżmy, że mamy klasy odpowiedzialne za podróż samochodem i statkiem:

class Car {
    drive() {
        console.log("I can drive");
    }
}
class Ship {
    sail() {
        console.log("I can sail");
    }
}

Chcąc dodać nową klasę, wzorowaną na amfibii, nie możemy zdefiniować standardowego dziedziczenia z tych dwóch klas z pomocą słówka extends. Zamiast tego, wystarczy wesprzeć się słówkiem implements aby zadeklarować klasę będącą ich kombinacją oraz zadeklarować niezbędne metody:

class Amphibian implements Car, Ship {
    drive: () => void;
    sail: () => void;
}

Aby połaczyć deklaracje metod z implementacją, możemy wesprzeć się funkcją applyMixins:

applyMixins(Amphibian, [Car, Ship]);

Którą można zadeklarować jako:

function applyMixins(derivedClass: any, baseClasses: any[]) {
    baseClasses.forEach(baseClass => {
        Object.getOwnPropertyNames(baseClass.prototype).forEach(name => {
            derivedClass.prototype[name] = baseClass.prototype[name];
        });
    });
}

W efekcie powinniśmy uzyskać możliwość utworzenia nowej instancji obiektu odpowiedzialnego za sterowanie amfibią z możliwością poruszania się po lądzie i wodzie:

const amphibian = new Amphibian();
amphibian.drive();
amphibian.sail();