NestJS tip: type safety on parameter decorators

for NestJS v8 and v9

In NestJS we can create specialized kind of parameters decorators using the createParamDecorator function from @nestjs/common. For example:

import { createParamDecorator } from ‘@nestjs/common’

export const CurrentUser = cre…


This content originally appeared on DEV Community and was authored by Micael Levi L. C.

for NestJS v8 and v9

In NestJS we can create specialized kind of parameters decorators using the createParamDecorator function from @nestjs/common. For example:

import { createParamDecorator } from '@nestjs/common'

export const CurrentUser = createParamDecorator<
  keyof User | undefined, // the type of `data`
  ExecutionContext, // the type of `ctx`
>(
  (data, ctx) => {
    const request = ctx.switchToHttp().getRequest()
    const user = request.user
    return typeof data === 'undefined'
      ? user[data]
      : user
  }
)

And then you can use that CurrentUser parameter decorator later in controller class's method, as follows:

// ...
@Get()
getCurrentUser(
  @CurrentUser() user: User,
  @CurrentUser('name') username: string,
) {
  return { user, username }
}

The issue

If your project has a bunch of those decorators, it might be hard to know what would be the type of their resolved values, right? I mean, how do you know that @CurrentUser() is a "bind" for request.user without some documentation or by reading the source? Also, what is the type of that request.user? Due to how TypeScript legacy decorators works, there's no way to typescript compiler infer some type from such param decorator.

My solution

You could see in my other article that I've leverage on TypeScript declaration merging feature like this:

basic demo

Along with generics, we can now easily couple the decorator with "its" type.

We just need to declare and export a type alias with the same name of our param decorator. See:

import { createParamDecorator } from '@nestjs/common'

export const CurrentUser = createParamDecorator<
  keyof User | undefined, // the type of `data`
  ExecutionContext, // the type of `ctx`
>(
  (data, ctx) => {
    const request = ctx.switchToHttp().getRequest()
    const user = request.user
    return typeof data === 'undefined'
      ? user[data]
      : user
  }
)

// -------- THIS IS NEW:
export type CurrentUser<Prop extends keyof User | undefined = undefined> =
  Prop extends keyof User ? User[Prop] : User
@Get()
getCurrentUser(
  @CurrentUser() user: CurrentUser,
  @CurrentUser('name') username: CurrentUser<'name'>
) {
  return { user, username }
}

Advantages

The ones I've seen so far:

  1. No one needs to recall what is the expected type of the resolved value by those parameters decorators. Just use the same name of the decorator.
  2. One source of truth of the expected type of such param decorator. If we change the implementation of that decorator in the future (and also the type of the returned object), we won't have to touch other parts of our codebase (unless we got some breaking change, of course).
  3. No need to import multiple types just for the sake of type safety.

Disadvantages

The ones I've seen so far:

  1. I didn't see this pattern often in the wild, so I won't expect it to be intuitive.
  2. If you use some pipe like this: @CurrentUser(MyPipe) somethingElse: any, that somethingElse parameter might not have the CurrentUser type anymore. So this pattern is restrict to those decorators that are not meant to use with pipes.
  3. User type is clear than CurrentUser one if you are familiar with User entity already. Thus, by reading the code outside of some code editor, it migth be a bit hard to find what that CurrentUser mean. But I think that this is just a matter of getting used of.


This content originally appeared on DEV Community and was authored by Micael Levi L. C.


Print Share Comment Cite Upload Translate Updates
APA

Micael Levi L. C. | Sciencx (2023-05-20T16:52:14+00:00) NestJS tip: type safety on parameter decorators. Retrieved from https://www.scien.cx/2023/05/20/nestjs-tip-type-safety-on-parameter-decorators/

MLA
" » NestJS tip: type safety on parameter decorators." Micael Levi L. C. | Sciencx - Saturday May 20, 2023, https://www.scien.cx/2023/05/20/nestjs-tip-type-safety-on-parameter-decorators/
HARVARD
Micael Levi L. C. | Sciencx Saturday May 20, 2023 » NestJS tip: type safety on parameter decorators., viewed ,<https://www.scien.cx/2023/05/20/nestjs-tip-type-safety-on-parameter-decorators/>
VANCOUVER
Micael Levi L. C. | Sciencx - » NestJS tip: type safety on parameter decorators. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/05/20/nestjs-tip-type-safety-on-parameter-decorators/
CHICAGO
" » NestJS tip: type safety on parameter decorators." Micael Levi L. C. | Sciencx - Accessed . https://www.scien.cx/2023/05/20/nestjs-tip-type-safety-on-parameter-decorators/
IEEE
" » NestJS tip: type safety on parameter decorators." Micael Levi L. C. | Sciencx [Online]. Available: https://www.scien.cx/2023/05/20/nestjs-tip-type-safety-on-parameter-decorators/. [Accessed: ]
rf:citation
» NestJS tip: type safety on parameter decorators | Micael Levi L. C. | Sciencx | https://www.scien.cx/2023/05/20/nestjs-tip-type-safety-on-parameter-decorators/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.