Рассмотрим следующий класс:
export class Foo {
id: string;
static readonly questionKeyPrefix: string;
constructor(id: string, _key: string) {
this.id = id;
if (!Foo.questionKeyPrefix) {
// Error: Cannot assign to 'questionKeyPrefix' because it is a read-only property
Foo.questionKeyPrefix = _key;
}
}
}
Когда я пытаюсь установить questionKeyPrefix, которое является статическим свойством только для чтения, оно соответствует. Я также добавляю условие, чтобы оно было установлено только один раз!
Если убрать статику, все будет хорошо!
Есть идеи, как решить эту проблему?
В моем реальном сценарии Foo — это абстрактный базовый класс, и каждый производный класс имеет свой собственный уникальный ключ для соответствующего словаря. Чтобы упростить инициализацию, лучше было бы сделать это в конструкторе. В противном случае существует риск того, что разработчики могут забыть вызвать другие статические методы, необходимые для инициализации этого свойства.
@kaya3 в C# я бы использовал статический конструктор, но в машинописном тексте ничего подобного нет!
Но этот код не будет предоставлять разные ключи для разных подклассов, все конструкторы будут присваивать одно и то же поле базового класса.
@kaya3 Почему? Я ожидаю, что в foo1: Foo и foo2: Foo у foo1 и foo2 разные ключи. Я ошибаюсь?
Как разные экземпляры могут иметь разные ключи, если это статическое свойство?
@kaya3 Вы правы, похоже, моя проблема сложнее, чем я думал. Вероятно, мне нужно добавить это статическое свойство в каждый подкласс. Но это также требует огромного рефакторинга, поскольку у меня большое приложение.
Или вы можете просто сделать это свойством экземпляра. Или, если вас беспокоит добавление дополнительных полей к каждому объекту, сделайте это методом с помощью get.
@kaya3 На самом деле мне нужно быть статичным для каждого подкласса



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


В TS вы можете использовать статические блоки для инициализации статических членов.
abstract class Foo {
id: string;
static questionKeyPrefix: string = "";
constructor(id: string, _key: string) {
this.id = id;
}
}
class Bar extends Foo {
static {
Foo.questionKeyPrefix += "abc";
}
}
console.info(Foo.questionKeyPrefix);
К сожалению, вы Не можете назначить статику только для чтения в статических блоках #56584
Спасибо за ответ!
То, как ваш код спроектирован на данный момент, не может работать, потому что у вас есть статическое свойство, значение которого может меняться каждый раз при вызове конструктора. Таким свойством быть не может readonly, поскольку можно наблюдать изменение его значения после инициализации.
Однако из комментариев кажется, что на самом деле это не моделирует то, чего вы пытаетесь достичь, потому что вы хотите, чтобы это свойство имело разное значение для каждого подкласса, а не другое значение для каждого экземпляра.
Самое простое решение — сделать его свойством экземпляра и просто присвоить этому свойству экземпляра соответствующее значение на основе его подкласса. Свойство экземпляра не обязательно должно быть параметром конструктора для каждого подкласса; вы можете передать его из конструктора подкласса:
class Base {
// instance field
readonly key: string;
constructor(_key: string) {
this.key = _key;
}
}
class Foo extends Base {
constructor() {
super('Foo');
}
}
class Bar extends Base {
constructor() {
super('Bar');
}
}
Альтернативный вариант, если вас беспокоит, что это свойство (например, потому что оно отображается при сериализации объекта), — сделать это «виртуальным» свойством с помощью get:
abstract class Base {
abstract readonly key: string;
}
class Foo extends Base {
get key() {
return 'Foo';
}
}
class Bar extends Base {
get key() {
return 'Bar';
}
}
Поскольку геттер объявляется для каждого подкласса, значение указывается для каждого подкласса, а не для каждого экземпляра.
Вообще говоря, «статика для каждого подкласса» не очень полезна, поскольку к статическим свойствам обычно не осуществляется полиморфный доступ. Это имело бы смысл только в том случае, если бы сами классы передавались как значения, например.
interface KeyedClass {
readonly key: string;
}
class Foo {
static readonly key = 'Foo';
}
class Bar {
static readonly key = 'Bar';
}
function logKey(cls: KeyedClass) {
console.info(cls.key);
}
logKey(Foo);
logKey(Bar);
Если вы этого не делаете, то нет смысла делать что-то «статическим для каждого класса», потому что вы не можете получить к нему полиморфный доступ из контекста экземпляра. this.key не будет работать и Base.key не является полиморфным; вы просто получите значение статического свойства базового класса, независимо от того, к какому подклассу принадлежит this.
Спасибо за ответ!
Почему вы хотите назначить его в конструкторе, если он статический? Это для ленивой инициализации?