Декораторы свойств TypeScript

Я хочу изолировать проверку модели внутри самого класса модели, без необходимости жесткого кодирования требуемых состояний (наши дизайнеры не знают, что требуется, просто им нужно подключить свойства). Я безуспешно пытаюсь использовать путь декоратора свойств. Конструктор перезаписывает то, что устанавливает декоратор. Это вообще возможно, я должен пойти об этом по-другому?

модель.ts

@Required
name: string;

hobbies: string;

constructor(dto?: any) {
    this.name = dto.name; // This clears my "required" property
    this.hobbies = dto.hobbies;
}

декоратор.ts

function Required(target: any, key: string) {
    Object.defineProperty(target, "required", { value: true });
}

Чего я надеюсь добиться...

*.html

<input name = "name" [(ngModel)] = "model.name" [required] = "model.name.hasOwnProperty('required')">

Я также пробовал играть с самим прототипом String, чтобы инициализировать это свойство, но конструктор по-прежнему очищает все, что устанавливается.

String.prototype["required"] = false;

Я не понимаю, как вы собираетесь использовать/создавать это. Не могли бы вы создать минимальный воспроизводимый пример на stackblitz.com? Я понимаю, что код не будет работать, но он передаст намерение.

Igor 07.03.2019 19:32
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
1
925
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете хранить дополнительную информацию в таком свойстве. Присвоенное свойство будет заменено новым значением, ничто из того, что вы назначаете, кроме прототипа класса (а target является prototype не экземпляром класса), не будет доступно после присвоения нового значения.

Решением было бы добавить дополнительное свойство, назовем его meta, которое могло бы содержать эти метаданные (и другие метаданные свойства по мере необходимости). Вы даже можете ввести его правильно, используя сопоставленные типы. Это решение довольно близко к желаемому результату:

class Model {
    readonly meta!: Metadata<Model>
    @Required
    name: string;

    hobbies: string;

    constructor(dto?: any) {
        this.name = dto.name; // This clears my "required" property
        this.hobbies = dto.hobbies;
    }
}
type Metadata<T> = Partial<Record<keyof T, PropertyMetadata>>
type PropertyMetadata = {
    required?: boolean
}
function Required<T extends { meta: Metadata<T> }, TKey extends keyof T>(target: T, key: TKey) {
    let meta = target.meta || (target.meta = {});
    let propMeta = meta[key] || (meta[key] = {})
    propMeta!.required = true
}

console.info(new Model({}).meta.name!.required);

Обратите внимание, что meta может быть неопределенным, если у вас нет метаданных. И метаданные для свойства также могут быть неопределенными, поэтому в шаблоне angular вы должны получить к ним доступ, используя ?: model.meta?.name?.required. Вы также можете сделать что-то более интересное, назначив Proxy вместо {}meta, но здесь я пошел простым путем.

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