Julián
Julián

Reputation: 328

Typescript decorator mess

Is there a way to solve massive decorator use inside classes?

Here's an example of a single property of a class in my NestJS app, with an incomplete swagger documentation decorator:

  @ApiModelProperty({
    description: 'description',
  })
  @Expose()
  @MaxLength(100, { message: 'message' })
  @IsString({ message: 'message' })
  @ValidateIf(address=> address.id !== null)
  @NotEquals(undefined, { message: 'message' })
  address: string;

This gets huge and ugly in no time. Any way to make the code look cleaner, defining the decorators in another file, maybe?

Upvotes: 4

Views: 1399

Answers (3)

zemil
zemil

Reputation: 5066

This good nestjs util helped in my case, maybe it helps you:

import { applyDecorators } from '@nestjs/common';

expose function ComposedDecorator(options: any) {
  return applyDecorators(
    Decorator1(),
    Decorator2(),
    AnotherDecoratorYouWant(),
  )
}

And then:

@ComposedDecorator(options)
// methodOrClassOrProperty

Upvotes: 1

ACampos
ACampos

Reputation: 26

Not really sure for how long this has existed under nestjs/common library, but I stumbled with this issue and in case someone else stumbles with this. After requesting help on their official discord, jmcdo29 suggested https://docs.nestjs.com/custom-decorators#decorator-composition which seems like the way to go.

Upvotes: 1

viniciusjssouza
viniciusjssouza

Reputation: 1275

Decorators are regular typescript functions. You can try to compose multiple decorators into a single one. For exemple, you could mix the validation ones into a single decorator, like this:

function apiStringField(maxLength: number, message: string, description?: string) {
  return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { 
      ApiModelProperty()(target, propertyKey, descriptor)
      Expose()(target, propertyKey, descriptor)
      MaxLength(maxLength, { message })(target, propertyKey, descriptor) 
      IsString({ message })(target, propertyKey, descriptor)
      NotEquals(undefined, { message })(target, propertyKey, descriptor) 
  }
}

And, use it like this (after importing it):

@apiStringField(100, 'message', 'description')
address: string;

Upvotes: 9

Related Questions