نکته NestJS: ایمنی را در تزئینات پارامتر تایپ کنید
برای NestJS v8 و v9
در NestJS میتوانیم نوع خاصی از پارامترهای تزئینی را با استفاده از آن ایجاد کنیم createParamDecorator تابع از @nestjs/common. مثلا:
import { createParamDecorator, ExecutionContext } 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
}
)
و سپس می توانید از آن استفاده کنید CurrentUser پارامتر decorator بعداً در متد کلاس کنترلر به صورت زیر است:
// ...
@Get()
getCurrentUser(
@CurrentUser() user: User,
@CurrentUser('name') username: string,
) {
return { user, username }
}
موضوع
اگر پروژه شما دارای دسته ای از آن دکوراتورها باشد، ممکن است سخت باشد که بدانید نوع ارزش های حل شده آنها چیست، درست است؟ یعنی از کجا میدونی @CurrentUser() یک “پیوند” برای request.user بدون سند یا با خواندن منبع؟ همچنین نوع آن چیست request.user? با توجه به نحوه کار دکوراتورهای قدیمی TypeScript، هیچ راهی برای استنباط کامپایلر تایپ اسکریپت از چنین دکوراتورهایی وجود ندارد.
راه حل من
شما می توانید در مقاله دیگر من ببینید که من از ویژگی ادغام اعلان TypeScript مانند زیر استفاده کرده ام:

همراه با ژنریک ها، اکنون می توانیم به راحتی دکوراتور را با نوع “خود” جفت کنیم.
ما فقط باید یک نوع نام مستعار را با همان نام دکوراتور param خود اعلام و صادر کنیم. دیدن:
import { createParamDecorator, ExecutionContext } 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 }
}
مزایای
اونایی که تا الان دیدم:
- هیچ کس نیازی به یادآوری ندارد که مقدار مورد انتظار تعیین شده توسط آن پارامترها چیست. فقط از همان نام دکوراتور استفاده کنید.
- یکی از منابع حقیقت از نوع مورد انتظار چنین پارا دکوراتور. اگر در آینده اجرای آن دکوراتور (و همچنین نوع شیء برگشتی) را تغییر دهیم، دیگر نیازی به لمس سایر قسمتهای پایگاه کد خود نخواهیم داشت. (البته مگر اینکه تغییرات اساسی داشته باشیم).
- نیازی به وارد کردن چندین نوع فقط به خاطر ایمنی نوع نیست.
معایب
اونایی که تا الان دیدم:
- من این الگو را اغلب در طبیعت ندیدم، بنابراین انتظار ندارم که شهودی باشد.
- اگر از لوله ای مانند این استفاده می کنید:
@CurrentUser(MyPipe) somethingElse: any، آنsomethingElseممکن است پارامتر نداشته باشدCurrentUserدیگر تایپ کنید بنابراین این الگو به آن دسته از دکوراتورهایی محدود می شود که قرار نیست با لوله ها از آنها استفاده شود. -
Userنوع واضح است ازCurrentUserیکی اگر آشنایی داریدUserموجودیت در حال حاضر بنابراین، با خواندن کد خارج از برخی از ویرایشگرهای کد، ممکن است کمی سخت باشد که آن را پیدا کنیدCurrentUserمنظور داشتن. اما من فکر می کنم که این فقط یک موضوع عادت کردن است.



