Skip to content

自定义装饰器

Nest 内置了许多装饰器,大多数功能都是通过装饰器来实现的。如果装饰器不满足需求的时候,可以自己开发,即自定义装饰器。

自定义装饰器

首先,创建个 decorator。这个就是我们自定义的装饰器。

ts
import { SetMetadata } from '@nestjs/common'

export const Aaa = (...args: string[]) => SetMetadata('aaa', args)

新建 Guard 来做判断,可以获取到 Metadata。

ts
@Injectable()
export class BbbGuard implements CanActivate {
  @Inject(Reflector)
  private reflector: Reflector
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    console.log(this.reflector.get('aaa', context.getHandler()))

    return true
  }
}

那么只要这样使用,可以通过装饰器来设置 Metadata。

ts
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  @Aaa('admin')
  @UseGuards(BbbGuard)
  getHello(): string {
    return this.appService.getHello()
  }
}

合并装饰器

当装饰器太多的时候,我们也可以实现合并装饰器。

下面的自定义装饰器通过 applyDecorators 合并了 Get、Aaa 和 UseGuard。

ts
import { Get, UseGuards, applyDecorators } from '@nestjs/common'
import { Aaa } from 'src/aaa/aaa.decorator'
import { BbbGuard } from 'src/bbb/bbb.guard'

export const Ccc = (path, role) =>
  applyDecorators(Get(path), Aaa(role), UseGuards(BbbGuard))

自定义参数装饰器

装饰器也能实现自定义参数。比如这个装饰器,可以在响应中返回字符串。

ts
export const Aaa = createParamDecorator(
  (data: string, ctx: ExecutionContext) => {
    return 'ccc'
  },
)
ts
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(@Aaa() a): string {
    return a
  }
}

回头看看装饰器的参数,data 是传入的参数;而 ExecutionContext 之前用过,可以从中取出 Response、Request 等。那么,如 @Param、@Query 等内置的装饰器我们也能自己实现。

比如,现在来实现一个 Query。

ts
export const Aaa = createParamDecorator(
  (key: string, ctx: ExecutionContext) => {
    const req: Request = ctx.switchToHttp().getRequest()

    return req.query[key]
  },
)
ts
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(@Aaa('aaa') aaa): string {
    console.log(aaa)

    return this.appService.getHello()
  }
}

Class 装饰器

Class 的装饰器上同,也能自定义。

ts
export const Aaa = () => Controller('aaa')
ts
@Aaa()
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello()
  }
}

可以看到,路径已经应用成功。

Released under the MIT License.