Страницы

Поиск по вопросам

четверг, 9 апреля 2020 г.

Имитация множественного наследования

#наследование #typescript #множественное_наследование #mixins #прототипное_наследование

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

Да, я понимаю, что это не полноценное наследование, но для решения задачи этого хватает.

Проблема в другом. Как заставить тайпскрипт воспринимать копируемые методы?

class First {
  someMethod() {
    console.log('someMethod from First');
  }
}

function Second() {
  console.log('Second');
}

Second.prototype.doSmth = function () { 
  console.log('doSmth from Second');
}

interface IBoth {
  someMethod()
  doSmth()
}

class Both extends First /* implements IBoth */ {
  constructor() {
    console.log('constructor of Both');
    super();
    Second.call(this);
  }
}

for (let key in Second.prototype) {
  Both.prototype[key] = Second.prototype[key];
}


На самом деле, надо обеспечить видимость методов ещё на уровень дальше

class Final extends Both {
  doIt() {
    this.someMethod();
    //this.doSmth(); // Надо заставить видеть метод тут
    (this as any as IBoth).doSmth(); // Компилируется, но это ужас
  }
}


если при этом методы не будут видны из самого Both, то это годится.

Вот что я уже пробовал:


При попытке написать

class Both extends First implements IBoth {


возникает ошибка, что я не реализую методы интерфейса.
При переименовании Both в _Both и использовании

var Both = _Both as typeof _Both;


всё остаётся как было, что логично, поскольку тут никак не используется First.
При переименовании Both в _Both и использовании

var Both = _Both as typeof IBoth;


говорит, что не может найти имя IBoth.


Пробовал ещё несколько вариантов, но они совсем бредовые.
Что ещё можно сделать?



Попробовать можно тут: http://www.typescriptlang.org/Playground
Полный код для проверки

Запустить (код из правой панели) после добавления строки:

(new Final).doIt();


Вывод при запуске при раскомментированной строке this.doSmth();  

constructor of Both
Second
someMethod from First
doSmth from Second
doSmth from Second




PS: Этот вопрос на английском.
    


Ответы

Ответ 1



Интерфейс вообще не нужен, нужно просто объявить прототипное поле с нужным типом: doSmth: () => void Она видима как свойство, а не как метод, но это непринципиально. Полный код: class First { someMethod() { console.log('someMethod from First'); } } function Second() { console.log('Second'); } Second.prototype.doSmth = function () { console.log('doSmth from Second'); } class Both extends First { constructor() { console.log('constructor of Both'); super(); Second.call(this); } doSmth: () => void } for (let key in Second.prototype) { Both.prototype[key] = Second.prototype[key]; } class Final extends Both { doIt() { this.someMethod(); this.doSmth(); //Both.prototype.doSmth(); // ok //Final.prototype.doSmth(); // ok } } PS: Надо было гуглить не всяческие варианты с наследованием, а typescript class prototype variable - сразу нашёл подходящий вариант.

Комментариев нет:

Отправить комментарий