skoder
@skoder
web программист

Как расширить prototype класса в TypeScript после его объявления?

Доброго времени. Помогите решить задачку:
Есть класс
class Jodit {
 constructor(options) {}
}

идея такая, что каждый экземпляр этого класса при создании получает некие кастомные настройки. Которые добавляются к дефолтным. Раньше в JQuery плагинах я просто extend'ил 2 хеша - дефолтный и кастомный
class Jodit {
 static defaultOptions = {
     dog: 100,
     cat: 200
 };
 options: object
 constructor(options?: object) {
     this.options = extends(true, {}, Jodit.defaultOptions, options);
 }
}

let editor = new Jodit({
    dogs: 300
});


у этого подхода есть минусы: Нет автодополнения в IDE, редактор тупо не знает что у нас в options, да и сам TypeScript от этого сильно теряет в своей предсказуемости.
Второй огромный минус - defaultOptions для последнего проекта, огромный. Просто простыня из сотен опций. Получается, что для каждого экземпляра класса мы эту простыню дублируем, тратя драгоценную оперативку пользователя.

Закономерно я решил сделать так:

function Options() {
    
}
Options.prototype = {
    dog: 100,
    cat: 200
}
class Jodit {
 
 options: object
 constructor(options?: object) {
     let __options = new Options();
     this.options = extends(true, __options, options);
 }
}


пример работает, 2-ая проблема решена. Все настройки лежат в единственном экземпляре, и лишь нужные переопределяются. Но тут нет автохинтинга, редактору и TypeScript не подсказать что и откуда брать.
Второй вариант:
class Options {
    dog = 100
    cat = 200    
}

class Jodit { 
 options: Options;
 constructor(options?: object) {
     let __options = new Options();
     this.options = extends(true, __options, options);
 }
}

решена проблема 1, но теперь для каждого экземпляра Jodit будет создватся полная копия всех дефолтных свойств. Даже наследование через класс не решает проблему, потому что TypeScript транспилит наследование в полное копирование всех свойств.

Подскажите как мне быть, это вообще возможно?.
  • Вопрос задан
  • 967 просмотров
Пригласить эксперта
Ответы на вопрос 1
Можно использовать обобщения (generics):
interface Options {
    cats: number;
    dogs: number;
}

const defaultOptions: Options = { cats: 100, dogs: 100 };

class Jodit<O extends Options> {
    constructor(public options: O) {}
}

const jodit = new Jodit({ ...defaultOptions, mice: 1000 });

jodit.options.mice = 1024;


Если так не хочется, чтобы опции копировались, то для опций придётся заводить классы:
class Options {
    cats = 100;
    dogs = 100;
}

class Jodit<O extends Options> {
    constructor(public options: O) {}
}

class MiceOptions extends Options {
    mice = 1000;
}

const jodit = new Jodit(new MiceOptions());

jodit.options.mice = 1024;
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы