نکته 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
منظور داشتن. اما من فکر می کنم که این فقط یک موضوع عادت کردن است.