Перейти к содержанию

Закрытые поля определенные спецификацией ECMAScript

Помимо сокрытия полей класса от внешней среды с помощью модификатора доступа private, присущего исключительно TypeScript, существует возможность прибегнуть к механизму предусмотренному спецификацией ECMAScript. Для того чтобы воспользоваться им, идентификаторы скрываемых полей должны начинаться с символа решетки #.

Доступ к защищенному полю класса ограничивается областью видимости класса в котором оно объявлено, а при обращении к нему необходимо также указывать символ решетки.

class Animal {
  #isLife: boolean = true // защищенное поле класса

  get isLife() {
    return this.#isLife
  }
}

let animal = new Animal()
console.log(animal.isLife) // обращение к аксессору, а не защищенному полю

Поскольку доступ ограничивается областью видимости класса, потомки не могут обращаться к защищенным полям своих предков.

class Animal {
  #isLife: boolean = true // защищенное поле класса
}

/**
 * Error!
 *
 * Class 'Bird' incorrectly extends base class 'Animal'.
 * Property '#isLife' is not accessible outside class 'Animal' because
 * it has a private identifier.ts(18013)
 */
class Bird extends Animal {
  constructor() {
    super()
    this.#isLife
  }
}

В отличие от модификатора доступа private, этот механизм не может быть применён к методам класса, но так как за его появлением стоит спецификация ECMAScript, то он продолжает действовать в скомпилированной программе. Именно поэтому, в отличие от сценария с модификатором доступа private, потомки могут без страха нарушить ожидаемый ход выполнения программы и объявлять защищенные поля, чьи идентификаторы идентичны объявлениям в их супер-классах.

Сценарий с модификатором доступа private:

class Animal {
  private _isLife: boolean = true
}

/**
 * Error!
 *
 * Class 'Bird' incorrectly extends base class 'Animal'.
 * Types have separate declarations of a private property '_isLife'.ts(2415)
 */
class Bird extends Animal {
  private _isLife: boolean = false
}

Сценарий с защищенными полями предусмотренными спецификацией ECMAScript:

class Animal {
  #isLife: boolean = true
}

/**
 * Ok!
 */
class Bird extends Animal {
  #isLife: boolean = false
}

И в заключение, стоит упомянуть что существует несколько нюансов — один из них заключается в том, что закрытые поля нельзя объявлять непосредственно в конструкторе.

class Animal {
    // Parameter declaration expected.ts(1138)
    constructor(#isLife = true) {}
}

Другой нюанс связан с тем, что код содержащий закрытые поля класса может быть скомпилирован исключительно в версии es6 и выше.