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

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

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

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

Вы можете инициализировать значения свойств внутри конструктора. В этом нет проблем.

Bear Nithi 01.03.2019 10:49
но в angular это обескураживает откуда вы это взяли?
Jota.Toledo 01.03.2019 10:57
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
7
2
2 447
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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 = ""
    }
}

Но делает ли это readonly снова не только для чтения, должны ли мы вернуть состояние только для чтения?

Nguyen Phong Thien 01.03.2019 10:55

Я не уверен, что понимаю ваш вопрос. Readonly — это просто то, что проверяет компилятор. ref, pRef и pSaferRef - это просто ссылки на this, которые не типизированы как доступные только для чтения, и поэтому мы можем делать все, что захотим.. this.data по-прежнему доступен только для чтения, если вы попытаетесь получить к нему доступ.

Titian Cernicova-Dragomir 01.03.2019 10:57

Почему бы вам не использовать сеттер и геттер вместо 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;
  }
}

@trichetriche это не обходной путь, потому что это реальное использование геттеров и сеттеров, оно очень часто используется, в том числе при реализации некоторых нативных функций. readonly используется для инициализации переменной при ее объявлении, поэтому любое другое использование, отличное от этого, является фактическим обходным путем.

Cristian Traìna 01.03.2019 11:23

Геттеры и сеттеры не являются свойствами только для чтения. Они являются переменными средствами доступа. Так что да, это обходной путь. Мало того, вы на самом деле не пишете «только для чтения» в своем коде. Это показывает, что это обходной путь. Вы также реализуете пользовательскую ошибку, в то время как в TS уже есть ошибка для свойств только для чтения. Все эти причины подтверждают, что это обходной путь. А в JS у вас есть способы объявить переменные только для чтения. Опять же, я не говорю, что то, что вы говорите, неверно, я просто говорю, что это не решение, а обходной путь, и не чистый. Но его точно можно использовать!

user4676340 01.03.2019 11:28

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

...
    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.

Readonly properties can only be assigned in the constructor

Не правда

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

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

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

but in angular it is discouraged and sometimes impossible to use the constructor for certain initialization and instead the angular hook ngOnInit is used

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

Is there any way to mark ngOnInit as a constructor

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

so that I can use readonly for essentially immutable properties that are only assigned a single time in ngOnInit?

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

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

Ого, сегодня узнал кое-что новое. Спасибо! Изменю мой ответ. Однако, как будущее доказательство это? Могут ли изменения в машинописном тексте не сломать это?

Pärt Johanson 01.03.2019 11:15

Сам провел небольшое исследование. По-видимому, это такое же будущее, как и все остальное в экосистеме javascript, то есть свойство, доступное для записи, определяется javascript, а не чем-то, что добавляется машинописным текстом.

Pärt Johanson 01.03.2019 11:24

технически первые 2 «альтернативы», которые вы представляете, являются вариантами инициализации конструктора, поскольку они переводятся в таковые.

Jota.Toledo 01.03.2019 11:27

@nosnahoj-trap означает ?

user4676340 01.03.2019 11:28

Я имел в виду использование Object.defineProperty

Pärt Johanson 01.03.2019 11:29

@ Jota.Toledo Я не спорю с этим, но если вы хотите зайти так далеко, они на самом деле не только для чтения, так что давайте сосредоточимся на машинописном тексте!

user4676340 01.03.2019 11:30

@nosnahoj-trap Да, это функция javascript, а не машинописный текст, но я не понимаю, что вы хотите сказать, поэтому мне нужно больше объяснений! (не носитель языка, я мог что-то упустить в вашем предложении)

user4676340 01.03.2019 11:31

@nosnahoj-trap О, я не видел, чтобы ты редактировал свой первый комментарий. Теперь ваши комментарии имеют больше смысла, ахах. Итак, чтобы ответить вам (даже если вы уже нашли ответ), да, это перспективно!

user4676340 01.03.2019 11:43

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

Simon Hirsig 02.03.2019 11:20

@Simon Javascript не имеет свойств только для чтения. Вы можете объявить переменную только для чтения и использовать метод определения свойства, чтобы присвоить ей новую переменную. Вы также можете ввести переменную как любую, чтобы изменить ее значение, как случайную переменную. Но есть только один способ правильно создать экземпляр, и это первый. Если вы хотите изменить значение свойства, доступного только для чтения, то оно не является свойством только для чтения. Подумайте о том, чтобы найти другой дизайн кодирования, вместо того, чтобы пытаться обойти его.

user4676340 02.03.2019 11:30

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