Свойства только для чтения и ngOnInit

Свойства только для чтения могут быть назначены только в конструкторе, но в angular это не рекомендуется, и иногда невозможно использовать конструктор для определенной инициализации, и вместо этого используется угловой хук ngOnInit. Есть ли способ пометить ngOnInit как конструктор в отношении атрибута readonly, чтобы я мог использовать readonly для практически неизменяемых свойств, которые назначаются только один раз в ngOnInit?

редактировать: уточнить: я не ищу альтернативных способов объявить свойства только для чтения. Я хочу объявить их обычным способом. Что-нибудь еще, я думаю, не стоило бы идти на компромисс в удобочитаемости, чтобы получить эту статическую проверку. Я надеялся, что будет какая-то аннотация, как если бы tslint игнорировал неизменность внутри ngOnInit.

Из ответов до сих пор, я думаю, назначив их как (this as any).foo = bar; является наиболее близким к тому, что я хотел бы сделать, хотя я думаю, что это все-таки уродливее, чем просто оставить только чтение.

4 ответа

Решение

Вы не можете пометить метод как конструктор, для этого просто нет синтаксиса. Вы можете сломать readonly которая является просто проверкой времени компиляции с использованием утверждения типа any и доступ к любой общественной / частной собственности, которую вы хотите, небезопасным способом. Вы также можете использовать сопоставленный тип, чтобы сделать его изменяемым, но он работает только для открытых свойств:

type Mutable<T> = { -readonly [ P in keyof T]: T[P] }

class Foo {
    public readonly data: string;
    private readonly pdata: string;
    public init() {
        const ref: Mutable<this> = this;
        ref.data = "" 
        const pRef = this as any;
        pRef.pdata = ""

        const pSaferRef: { pdata: string } = this as any;
        pSaferRef.pdata = ""
    }
}

Свойства только для чтения могут быть назначены только в конструкторе

Не правда

class MyClass {
  readonly prop1 = 'prop1';
  constructor(
    public readonly prop2 = 'prop2'
  ) {
  }

  ngOnInit() {
    Object.defineProperty(this, 'prop3', { wirtable: false, value: 'prop3'});
  }
}

Как видите, уже есть 3 способа их определения. И, вероятно, больше!

но в angular не рекомендуется и иногда невозможно использовать конструктор для определенной инициализации, и вместо этого используется угловой хук ngOnInit

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

Есть ли способ пометить ngOnInit как конструктор

Конструктор - это конструктор. Вы не можете определить метод, который будет конструктором. Вы можете вызвать только метод в конструкторе, но это не решит вашу проблему.

так что я могу использовать readonly для по существу неизменяемых свойств, которые назначаются только один раз в ngOnInit?

Ответ и суть: используйте ваш конструктор, как вам угодно. Поместите свои свойства только для чтения, если хотите.

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

Почему бы вам не использовать сеттер и геттер вместо readonly?

export class MyComponent {
  private _value: string;
  set value(v: string) {
    if (!this._value) {
      this._value = v;
    } else {
      throw new TypeError('Assignment to read-only variable');
    }
  }

  get value() {
    return this._value;
  }
}

Это хороший вопрос. Вы можете получить нечто подобное через сеттер:

...
    protected _pseudoReadonlyProp: number = -1 // or some other value, that marks unititialized state
    set pseudoReadonlyProp(a: number) {
        if(this._pseudoReadonlyProp != -1) {
           // throw some error here
        }
        this._pseudoReadonlyProp = a
    }
    get pseudoReadonlyProp(): number {
        return this._pseudoReadonlyProp
    }
...

Еще один способ получить аналогичное поведение - заключить в класс доступный только для чтения член, поместить его в свой компонент и создать новый экземпляр класса в ngInit или какой-либо другой функции инициализации компонента.

Учитывая, что Object.defineProperty существует, лучшим способом было бы использовать его, как указано @trichetriche

Другие вопросы по тегам