Что такое множественное наследование в TypeScript

Ответ

TypeScript не поддерживает множественное наследование напрямую, как некоторые другие языки (например, C++). Однако есть несколько способов добиться похожего поведения:

  1. Миксины - паттерн, позволяющий комбинировать функциональность из нескольких классов:
class Disposable {
  dispose() { console.log('Disposed'); }
}

class Activatable {
  activate() { console.log('Activated'); }
}

class SmartObject implements Disposable, Activatable {
  dispose: () => void;
  activate: () => void;
}

applyMixins(SmartObject, [Disposable, Activatable]);
  1. Композиция (предпочтительный способ) - использование других классов через включение:
class Engine {
  start() { /* ... */ }
}

class Wheels {
  rotate() { /* ... */ }
}

class Car {
  private engine = new Engine();
  private wheels = new Wheels();

  drive() {
    this.engine.start();
    this.wheels.rotate();
  }
}

Лучше использовать композицию, так как она более гибкая и проще в поддержке, чем классическое множественное наследование.

Ответ 18+ 🔞

А, ну это ж классика, блядь! TypeScript и его танцы с бубном вокруг множественного наследования, ёпта! Ситуация, знаешь ли, как с трёхногим табуретом — вроде и сесть можно, но балансировать, сука, приходится.

Смотри, в натуре, TypeScript тебе прямо в лоб, как хороший мужик, говорит: «Нет, браток, хуй тебе, а не множественное наследование из коробки, как у этих ваших вырожденцев на C++». Но русский человек, он же хитрожопый, он всегда найдёт, блядь, лазейку! И их тут, на самом деле, целых две основных, как дырки в заборе.

Первый способ — это миксины. Ну, типа, такая полупидорская подстава, но работает, блядь!

class Disposable {
  dispose() { console.log('Disposed'); }
}

class Activatable {
  activate() { console.log('Activated'); }
}

class SmartObject implements Disposable, Activatable {
  dispose: () => void;
  activate: () => void;
}

applyMixins(SmartObject, [Disposable, Activatable]);

Видишь эту хуйню? SmartObject вроде как и Disposable, и Activatable. Но это ж пиздёж чистой воды, чувак! Он просто говорит, что он их реализует (implements), а реальную работу делает какая-то ёбанная функция applyMixins, которая, как шустрый воришка, натырит методы из одних классов и впихнёт их в другой. Хитро, да? Но и дохуя заморочно, блядь. Чувствуешь подвох? Подозрение ебать чувствую!

Второй способ — композиция. А вот это, я тебе скажу, охуенно правильный путь, мудя! Забудь про это ваше «наследуюсь от папы и мамы сразу». Лучше бери и включай нужные штуки напрямую, как здоровый мужик!

class Engine {
  start() { /* ... */ }
}

class Wheels {
  rotate() { /* ... */ }
}

class Car {
  private engine = new Engine();
  private wheels = new Wheels();

  drive() {
    this.engine.start();
    this.wheels.rotate();
  }
}

Смотри, какая красота, блядь! У тебя есть Car. В нём живёт, сука, Engine и Wheels. И он ими рулит! Хочешь «завестись» — дерни за engine.start(). Никакой ебли с предками, никакой путаницы, кто какой метод переопределил. Всё прозрачно, как слёзы ребёнка. И если завтра тебе понадобится реактивный двигатель вместо бензинового — хуй с ним, просто впихни другой Engine, и не надо перелопачивать всю иерархию наследования, которая уже, блядь, как паутина, опутала всё.

Короче, вывод простой, как три копейки: забей на попытки сделать множественное наследование и юзай композицию. Это надёжнее, гибче и не доведёт тебя до состояния «терпения ноль ебать», когда через полгода надо будет разбираться, откуда, нахуй, в классе взялся метод dispose(). Чистый код, ядрёна вошь!