Множественное наследование — это функция, при которой класс может расширять более одного базового класса.

Проблема

Что, если мы хотим создать разные компоненты пользовательского интерфейса, такие как «кнопка», «ввод», «элемент списка действий» и «пункт меню»? Все эти компоненты имеют разное поведение и внешний вид. Однако все они могут быть отключены, могут иметь базовый цвет, а последние два — общий базовый класс. Мы хорошие разработчики и хотим писать чистый и СУХОЙ код. Итак, давайте посмотрим, что мы можем сделать в этой ситуации.

Расширение

Допустим, у нас есть три класса, которые предоставляют три метода, и мы хотим создать четвертый класс, который будет предоставлять все эти три метода.

Наиболее логичным решением будет сделать что-то вроде этого:

Однако это не сработает. Typescript допускает расширение только одного базового класса. Итак, нам нужно продлевать их один за другим в цепочке.

Все работает, и с этим можно жить, но что, если в некоторых из полученных классов нам не нужен метод b? Он у нас все равно будет, потому что класс C расширяет класс B и без него не будет метода a из класса A. Конечно, мы можем создавать комбинации классов, такие как класс AC, которые будут расширять A, а не расширять B и так далее, но такой код очень быстро станет нечитаемым и непригодным для сопровождения.

Состав

Вместо расширения мы можем составить наши классы внутри полученного.

Это решение довольно хорошее и настоятельно рекомендуется, если вы создаете компоненты в Angular. Но и у него есть свои ограничения. Что, если некоторые из этих классов имеют свойства или геттеры, к которым мы хотим обращаться непосредственно в нашем классе D? Или мы не хотим вызывать методы так долго?

Миксины

Typescript дает нам замечательный шаблон, позволяющий нам создать функцию, которая расширит базовый класс. Реализуем расширение классов A и C на D. И пусть наш класс A имеет защищенное свойство _propA и геттер для него.

Прежде всего, нам нужно сделать некоторые приготовления. Нам нужно определить тип Constructor и интерфейсы, которые реализуют классы A и C.

Теперь мы можем создать функцию миксина для класса A.

Давайте разберемся, что здесь происходит. Функция mixinA принимает в качестве аргумента анонимный класс и возвращает шаблон выражения класса, расширяющий класс, который мы предоставили в качестве аргумента. Внутри этого шаблона выражения мы определяем все свойства и методы, которые должны быть у класса A.

Теперь давайте создадим миксин для класса C.

А теперь давайте, наконец, создадим наш получившийся класс D.

Вы можете видеть, что класс D имеет все методы и свойства, унаследованные от классов A и C.

Потрясающий! А что, если мы хотим, чтобы наш класс D имел базовый класс в дополнение к классам A и C? Единственное, что нам нужно сделать, это просто определить его и передать mixinA в качестве аргумента.

Используя универсальный тип Constructor, мы можем ограничить, какой тип мы можем предоставить как base для функции миксина.

Заключение

Несмотря на ограничение JavaScript на расширение только одного класса, у нас есть способ решить проблему чисто и красиво. Мы можем использовать композиции или миксины в зависимости от поставленных перед нами задач.

Станьте компонуемым: создавайте приложения быстрее, как Lego

Bit – это инструмент с открытым исходным кодом для модульного и совместного создания приложений. Перейдите на компоновку, чтобы поставлять быстрее, более последовательно и легко масштабировать.

Подробнее

Создавайте приложения, страницы, пользовательский опыт и пользовательские интерфейсы как автономные компоненты. Используйте их, чтобы быстрее создавать новые приложения и возможности. Используйте любой фреймворк и инструмент в своем рабочем процессе. Делитесь, повторно используйте и сотрудничайте, чтобы строить вместе.

Помогите своей команде:

Микроинтерфейсы

Дизайн-системы

Совместное использование кода и повторное использование

Монорепо

Узнать больше