Комментарии 6
А ещё можно эти столбики декораторов сжимать, если там повторяющиеся общие паттерны действий у методов.
Например такой код:
@GetArrayWithCache('symbol/:id')
@InfluxTimeLog()
async getSymbol(@Headers() headers: object, @Param('id') id: string): TProxyItem {
return this.symbolsService.getById(id);
}
может иметь такой вот составной декоратор
export function GetArrayWithCache(path: string) {
return applyDecorators(
Get(path),
ApiOkResponse(ARRAY_RESPONSE_DOC),
ApiOperation(ARRAY_CACHE_DOC),
CheckNotFound(),
);
}
где applyDecorators это функция-склеиватель
export function applyDecorators(
...decorators: Array<ClassDecorator | MethodDecorator | PropertyDecorator>
) {
return <TFunction extends Function, Y>(
target: TFunction | object,
propertyKey?: string | symbol,
descriptor?: TypedPropertyDescriptor<Y>,
) => {
for (const decorator of decorators) {
if (target instanceof Function && !descriptor) {
(decorator as ClassDecorator)(target);
continue;
}
(decorator as MethodDecorator | PropertyDecorator)(
target,
propertyKey,
descriptor,
);
}
};
}
И, как видите, в составном декораторе можно передать параметры... в том числе и другие декораторы, если это нужно.
А ещё декораторами можно описывать апи и в итоге вместо писанины ручной валидации или конфигов или каких-либо других хитросплетений - мы можем просто сделать так
export class AccountListArgs {
@Property({
enum: EFieldsSortingAccounts,
description: 'orderBy',
})
@IsOptional()
@IsEnum(EFieldsSortingAccounts)
orderBy?: EFieldsSortingAccounts = EFieldsSortingAccounts.ID;
}
и, натравив туда пакеты class-transformer и class-validator с ходу отвалидировать на тип, енум, не обязательность наличия и ещё сверху сгенерировать swagger-схему и на лету её показать на отдельном урле с документацией.
В общем, если вы ещё не используете декораторы - время пришло.
В общем, если вы ещё не используете декораторы - время пришло.
На самом деле если вы ещё не используете TS декораторы – то сейчас самый неподходящий момент для начала их использования. Во-первых, core team разработчики TS называют декораторы одним из самых неудачных экспериментов (не зря они experimentalDecorators
). Во-вторых, как причина первого пункта, в ECMAScript на подходе нативные декораторы, которые имеют такой же синтаксис, но работают совершенно иначе. И как этот зоопарк дружить друг с другом пока что под большим вопросом.
Они удобные, это да. Но лично я сейчас предпочитаю императивный подход тогда, когда это уместно.
Ну, неудачный это эксперимент или нет, но это удобно, это работает, на этом множество фреймворков построено и кода написано. На столько что где-то это корпоративный легаси уже. И фатальных недостатков так то нет. Кроме того что обогнало оригинальный JS на несколько лет и теперь придется чуть поиграть с транспилерами.
А императивный или нет - всё же экономия времени и ресурсов слишком большая чтобы отказывать себе в удовольствии пользоваться декораторами, это как классы или лямбды, или тот же асинк-авейт - можно без них и в разных парадигмах даже что-то из этого там или сям отсутствует, но всё же это добавляет слишком много выразительности и удобства, чтобы пройти мимо. К тому же декораторы были обточены на многих других языках и пришли как устоявшийся в целом механизм, хоть и в итоге есть нюансы в различиях работы ванилы и тайпскрипта. Так то в ваниле и приватные методы с хешами совсем иначе работают, но в итоге они просто дополнили друг друга - классические ООП приватные методы от тайпскрипта и суровые на символе-указателе с хешом в имени и невидимые извне у ванилы. Посмотрим как тут слияние выйдет, но декораторы уже слишком плотно в обороте чтобы с ними что-то произошло.
Жду "карамелизаторов" и "лакираторов"
Если к члену класса прикреплены несколько декораторов, их выполнение происходит сверху вниз по очереди.
хмм, в моей шпаргалке записано так:
Если декораторы записываются в столбик, то вызываются они снизу вверх (при этом предварительное вычисление идёт сверху вниз)
Я сейчас только пытаюсь понять, с чем это едят, но у меня сложилось мнение, что
@dec1
@dec2
@dec3
Считается как
dec1(dec2(dec3()))
С одной стороны, функции вызываются сверху вниз, но если смотреть, чьё значение посчитается первым, то снизу вверх. Или я неправильно интерпретирую понятие выполнения функции, что вполне может быть.
Мощь декораторов TypeScript на живых примерах. Декорирование методов класса