TypeScript, как и многие объектно-ориентированные языки, как, например, Java или C#, не позволяет использовать напрямую множественное наследование. Мы можем реализовать множество интерфейсов в классе, но унаследовать его можем только от одного класса. Однако функциональность миксинов (mixins) частично позволяют унаследовать свойства и методы сразу двух и более классов.
Рассмотрим на примере. Пусть, у нас есть класс Animal, который представляет животное, и класс Movable, который представляет транспортное средство. Оба эти класса имеют свой уникальный функционал, который позволяет выполнять заложенные в них задачи. И также пусть у нас будет класс, который представляет лошадь - с одной стороны, лошадь является животным и наследует все черты, присущие животному, а с другой стороны, лошадь также можно использовать в качестве транспортного средства. То есть для создания подобного класса было бы неплохо унаследовать его сразу и от класса Animal, и от класса Movable. Решим эту задачу на языке TypeScript:
class Animal { feed():void { console.log("Кормим животное"); } } class Movable { speed: number=0; move(): void { console.log("Перемещаемся"); } } class Horse {} interface Horse extends Animal, Movable {} function applyMixins(derivedCtor: any, baseCtors: any[]) { baseCtors.forEach(baseCtor => { Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { derivedCtor.prototype[name] = baseCtor.prototype[name]; }); }); } applyMixins(Horse, [Animal, Movable]); let pony: Horse = new Horse(); pony.feed(); pony.move();
Чтобы класс Horse мог унаследовать методы классов Animal и Movable, определяется одноименный интерфейс Horse, который расширяет интерфейсы Animal и Movable:
interface Horse extends Animal, Movable {}
Но чтобы миксин мог унаследовать функционал, этого недостаточно. Нам еще надо использовать специальную функцию, которая перекопирует функционал из родительских классов в миксин:
function applyMixins(derivedCtor: any, baseCtors: any[]) { baseCtors.forEach(baseCtor => { Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => { derivedCtor.prototype[name] = baseCtor.prototype[name]; }); }); }
Затем применяем эту функцию:
applyMixins(Horse, [Animal, Movable]);
Первым параметром идет класс-миксин, а второй параметр - массив применяемых классов.