Модификаторы доступа класса в зависимости от ситуации

Есть ли какой-то способ указать, что определенный приватный метод или свойство публичен для определенных классов? Например:

class Parent {
    private [but public for Child] childrenContainer: HTMLElement; // сокрытый от всех, но видимый для дочерних
}

class Child {
    constructor(){
        parent.childrenContainer.appendChild( document.createElement('div') );
    }
}

Этого очень не хватает, когда внутренним (дочерним но не наследованным) экземплярам нужен доступ к приватному методу родителя. Без этой возможности приходится раскрывать многие приватные свойства и методы родителя, что совсем не нужно никому, кроме дочерних экземпляров, которые по смыслу являются частью реализации родителя.

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


Ответы (2 шт):

Автор решения: Alexey Ten

В Typescript есть «аварийный люк» для таких случаев. Можно получить доступ к приватному свойству при помощи квадратных скобок.

parent.childrenContainer // ошибка
parent['childrenContainer'] // ок

Впрочем на мой вкус, тут лучше бы подошёл метод родителя:

parent.addChild(document.createElement('div'))
→ Ссылка
Автор решения: Pavel Grishaev

Благодаря этому ответу нашёл приемлемый вариант решения, при котором 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 он не создавался как свойство заново каждый раз внутри конструктора родителя.

→ Ссылка