Parameter dekorator — parametrlarni belgilash

~15 daq · TypeScript · Dekoratorlar

NestJS da @Body(), @Param(), @Query() — parametr dekoratorlari. Ular metod parametrlarini HTTP so'rov qismlari bilan bog'laydi. Parametr dekorator — eng kam qo'llaniladigan, lekin DI frameworklari uchun muhim.


Parameter dekorator imzosi

type ParameterDecorator = (
  target:         Object, // prototype
  key:            string, // metod nomi
  parameterIndex: number  // parametr indeksi (0-dan)
) => void;

Parametr metadata saqlash

const paramMeta: Map<string, number[]> = new Map();

function KiritilganQiymat(target: any, key: string, index: number) {
  const mapKey = `${target.constructor.name}.${key}`;
  if (!paramMeta.has(mapKey)) paramMeta.set(mapKey, []);
  paramMeta.get(mapKey)!.push(index);
}

class UserController {
  topish(
    @KiritilganQiymat id: number,
                       faol: boolean,
    @KiritilganQiymat email: string
  ): string {
    return `${id}: ${email}`;
  }
}

paramMeta.get("UserController.topish"); // [0, 2] — id va email indekslari

NestJS @Body() misoli (sodda)

import "reflect-metadata";

const BODY_KEY = "body:params";

function Body(target: any, key: string, index: number) {
  const params: number[] = Reflect.getMetadata(BODY_KEY, target, key) || [];
  params.push(index);
  Reflect.defineMetadata(BODY_KEY, params, target, key);
}

class UserController {
  yaratish(@Body dto: { ism: string; email: string }): string {
    return `${dto.ism} yaratildi`;
  }
}

// Framework dto ni HTTP body dan olib, 0-indeksli parametrga uzatadi

Validatsiya bilan birga

function Majburiy(target: any, key: string, index: number) {
  const majburiylar: number[] =
    Reflect.getMetadata("majburiy", target, key) || [];
  majburiylar.push(index);
  Reflect.defineMetadata("majburiy", majburiylar, target, key);
}

function Tekshir(target: any, key: string, descriptor: PropertyDescriptor) {
  const asl = descriptor.value;
  descriptor.value = function(...args: any[]) {
    const majburiylar: number[] =
      Reflect.getMetadata("majburiy", target, key) || [];
    for (const i of majburiylar) {
      if (args[i] === undefined || args[i] === null) {
        throw new Error(`${key}: ${i}-parametr majburiy`);
      }
    }
    return asl.apply(this, args);
  };
}

class Xizmat {
  @Tekshir
  saqlash(@Majburiy ism: string, @Majburiy email: string): void {
    console.log(ism, email);
  }
}

new Xizmat().saqlash("Ali", undefined!); // ❌ xato

Xulosa

// Imzo
function MyDeco(target: Object, key: string, index: number): void { ... }

// Parametr indeksi
class A {
  fn(
    @Deco a: string,  // index 0
          b: number,  // index 1 — deco yo'q
    @Deco c: boolean  // index 2
  ) {}
}

// Asosan: metadata saqlash + method dekorator bilan birga ishlatish
// Frameworklar: NestJS @Body(), @Param(), @Query()

Parametr dekorator — metadata saqlaydi, o'zi hech narsani o'zgartirmaydi. Method dekorator bu metadata dan foydalanib mantiq qo'shadi.


Keyingi dars

58-dars: Declaration files — .d.ts yaratish, @types, module augmentation