Модификаторы доступа класса в зависимости от ситуации
Есть ли какой-то способ указать, что определенный приватный метод или свойство публичен для определенных классов? Например:
class Parent {
private [but public for Child] childrenContainer: HTMLElement; // сокрытый от всех, но видимый для дочерних
}
class Child {
constructor(){
parent.childrenContainer.appendChild( document.createElement('div') );
}
}
Этого очень не хватает, когда внутренним (дочерним но не наследованным) экземплярам нужен доступ к приватному методу родителя. Без этой возможности приходится раскрывать многие приватные свойства и методы родителя, что совсем не нужно никому, кроме дочерних экземпляров, которые по смыслу являются частью реализации родителя.
Здесь в примере я привёл только одно свойство, его можно передать в дочерний класс и без раскрытия, но часто бывает так, что свойств очень много, и если их передавать, то будет много лишнего кода.
Ответы (2 шт):
В Typescript есть «аварийный люк» для таких случаев. Можно получить доступ к приватному свойству при помощи квадратных скобок.
parent.childrenContainer // ошибка
parent['childrenContainer'] // ок
Впрочем на мой вкус, тут лучше бы подошёл метод родителя:
parent.addChild(document.createElement('div'))
Благодаря этому ответу нашёл приемлемый вариант решения, при котором private становится как public для дочерних классов. Может кому-то пригодится для реализации различных списков и подобных структур. Публичный интерфейс родительского класса при таком подходе остаётся чистым, так как не приходится раскрывать его поля для дочерних классов.
class Parent {
private childrenElements: Array<HTMLElement> = []; // Заметьте, что здесь private!
constructor(){
new Parent.Child(this);
}
private static Child = class Child {
private parent: Parent;
constructor( parent: Parent ){
this.parent = parent;
}
childMethod(): void {
// Но дочерний класс имеет доступ к родительскому private, как если бы он был public!
this.parent.childrenElements.push( document.createElement('div') );
}
}
}
Такой подход работает потому, что считается, что дочерний класс находится внутри области родительского класса (в его скоупе). И при любом выносе наружу это перестанет работать.
Нюанс - класс Child здесь сделан статичным, чтобы после компиляции в JS он не создавался как свойство заново каждый раз внутри конструктора родителя.