Инкапсуляция в TypeScript
Вопрос
Как скрыть внутреннее состояние объекта в TypeScript и насколько надёжен каждый способ?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
`private` и `protected`: только проверка компилятора, обходится `as any` и обращением по строке
`#поля`: настоящая приватность в рантайме, но не видны наследникам
Замыкание (фабричная функция): состояние недоступно снаружи совсем
`readonly` и `Readonly<T>` защищают от присваивания только при компиляции
Для неизменяемости в рантайме нужен `Object.freeze`
Что могут спросить следом
- Можно ли использовать
#полев наследнике? - Что видно в
JSON.stringifyдля каждого варианта? - Как это связано с проверкой
#x in obj?
Разбор
Есть три уровня. private и protected защищают только от честного кода: это проверка компилятора, в рантайме поле обычное, его видно в JSON.stringify и можно прочитать через as any. Поля с # приватны на уровне языка: снаружи класса к ним не обратиться, они не попадают в Object.keys и сериализацию. Ограничение: наследник их тоже не видит, для общего с наследниками состояния остаётся protected. Проверить, что объект создан этим классом, можно через #x in obj. Третий способ, замыкание: фабричная функция возвращает объект с методами, а состояние живёт в её локальных переменных. Что касается неизменяемости, readonly тоже только компилятор, в рантайме защищает Object.freeze. В прикладном коде мне обычно хватает private, а # беру для библиотечного кода, где важно, чтобы снаружи не полагались на внутренности.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.