برنامه نویسی

نکته 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 }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مزایای

اونایی که تا الان دیدم:

  1. هیچ کس نیازی به یادآوری ندارد که مقدار مورد انتظار تعیین شده توسط آن پارامترها چیست. فقط از همان نام دکوراتور استفاده کنید.
  2. یکی از منابع حقیقت از نوع مورد انتظار چنین پارا دکوراتور. اگر در آینده اجرای آن دکوراتور (و همچنین نوع شیء برگشتی) را تغییر دهیم، دیگر نیازی به لمس سایر قسمت‌های پایگاه کد خود نخواهیم داشت. (البته مگر اینکه تغییرات اساسی داشته باشیم).
  3. نیازی به وارد کردن چندین نوع فقط به خاطر ایمنی نوع نیست.

معایب

اونایی که تا الان دیدم:

  1. من این الگو را اغلب در طبیعت ندیدم، بنابراین انتظار ندارم که شهودی باشد.
  2. اگر از لوله ای مانند این استفاده می کنید: @CurrentUser(MyPipe) somethingElse: any، آن somethingElse ممکن است پارامتر نداشته باشد CurrentUser دیگر تایپ کنید بنابراین این الگو به آن دسته از دکوراتورهایی محدود می شود که قرار نیست با لوله ها از آنها استفاده شود.
  3. User نوع واضح است از CurrentUser یکی اگر آشنایی دارید User موجودیت در حال حاضر بنابراین، با خواندن کد خارج از برخی از ویرایشگرهای کد، ممکن است کمی سخت باشد که آن را پیدا کنید CurrentUser منظور داشتن. اما من فکر می کنم که این فقط یک موضوع عادت کردن است.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا