История вопроса
В TypeScript приватные свойства появились изначально с помощью модификатора private, а начиная с ECMAScript 2021 в JavaScript поддерживаются настоящие закрытые поля c помощью символа #. Основная цель — инкапсуляция данных, чтобы защитить внутренние детали класса от доступа извне.
Проблема
Модификатор private в TypeScript обеспечивает приватность только на этапе компиляции, но в скомпилированном JavaScript эти поля остаются доступными через прямой доступ к свойствам объекта. Это может привести к непреднамеренному изменению состояния объекта. ES Private Fields (#) полностью недоступны вне класса даже на уровне рантайма JS, что обеспечивает реальную защиту данных.
Решение
TypeScript поддерживает оба подхода. При выборе между ними ориентируйтесь на нужную степень защиты и ограничения на совместимость с версиями JS.
Пример кода:
class Example { private hidden: number; #trulyHidden: string; constructor() { this.hidden = 42; this.#trulyHidden = 'secret'; } getHidden() { return this.hidden; } getTrulyHidden() { return this.#trulyHidden; } } const x = new Example(); // x.hidden — ошибка в TS, но сработает через x['hidden'] в JS // x.#trulyHidden — синтаксическая ошибка даже в JS
Ключевые особенности:
private гарантирует приватность только на этапе компиляции TypeScript#field даёт настоящую приватность на уровне исполнения JavaScript# требует поддержки современного JS (ES2021+)Можно ли получить доступ к private полю класса TypeScript через прямое обращение в JS?
Да, можно, так как приватность реализована только на этапе компиляции. В исходном JS поле будет обычным свойством объекта. Например:
class A { private x = 1; } const a = new A(); console.log((a as any)["x"]); // 1
Можно ли использовать приватные поля с # в интерфейсах или описывать их с помощью type?
Нет, #private поля — часть только реализации класса и не могут быть описаны в интерфейсах, типах или использованы вне самого класса. Интерфейсы описывают только публичные члены.
Можно ли наследовать приватные поля, объявленные с помощью #?
Нет, такие поля вообще не доступны классам-наследникам. Только сам класс имеет к ним доступ:
class Parent { #foo = 123; } class Child extends Parent { // this.#foo = 444; // Ошибка }
private для защиты критичных данных — приводит к уязвимости при прямом доступеВ проекте для хранения паролей в классе User использовано поле private password. Один из разработчиков случайно получает доступ через user['password'] для дебага, а поле оказывается изменённым сторонним модулем.
Плюсы:
Минусы:
Разработчик использует ES private field #password. Теперь попытки обращения к полю через индексацию или в наследниках не проходят, безопасность данных обеспечена даже при использовании сторонних библиотек и инструментария.
Плюсы:
Минусы: