Class dekorator — sinfni o'zgartirish va kengaytirish

~20 daq · TypeScript · Dekoratorlar

NestJS da @Injectable() — classni DI konteyneriga ro'yxatdan o'tkazadi. @Controller("/users") — HTTP yo'lini belgilaydi. Bular — class dekoratorlar. Qanday ishlashini tushunish uchun o'zimiz yozamiz.


Class dekorator imzosi

type ClassDecorator = (target: Function) => void | Function;

target — classning o'zi (constructor funksiyasi).


Metadata qo'shish

function Versiya(n: string) {
  return function(target: Function) {
    (target as any).versiya = n; // class ga static xususiyat qo'shamiz
  };
}

@Versiya("1.0.0")
class API {}

(API as any).versiya; // "1.0.0"

Ro'yxatga olish

const xizmatRo_yxati: Map<string, Function> = new Map();

function Xizmat(nom: string) {
  return function(target: Function) {
    xizmatRo_yxati.set(nom, target);
    console.log(`Ro'yxatga qo'shildi: ${nom}`);
  };
}

@Xizmat("foydalanuvchi")
class FoydalanuvchiXizmat {}

@Xizmat("mahsulot")
class MahsulotXizmat {}

xizmatRo_yxati.get("foydalanuvchi"); // FoydalanuvchiXizmat class

Classni kengaytirish

Dekorator yangi class qaytarsa — asl classni almashtiradi:

function Kuzatuvchi<T extends { new(...args: any[]): {} }>(Base: T) {
  return class extends Base {
    yaratilganVaqt = new Date();

    constructor(...args: any[]) {
      super(...args);
      console.log(`${Base.name} instansi yaratildi`);
    }
  };
}

@Kuzatuvchi
class Foydalanuvchi {
  constructor(public ism: string) {}
}

const u = new Foydalanuvchi("Jasur");
// "Foydalanuvchi instansi yaratildi"
(u as any).yaratilganVaqt; // Date

NestJS @Controller misoli (sodda)

const routelar: Map<Function, string> = new Map();

function Controller(prefiks: string) {
  return function(target: Function) {
    routelar.set(target, prefiks);
  };
}

@Controller("/users")
class UsersController {}

routelar.get(UsersController); // "/users"

Tez-tez uchraydigan xatolar

Dekoratorni yoqmasdan ishlatish:

@MyDecorator
class A {} // ❌ — experimentalDecorators: true bo'lmasa xato

Target turini noto'g'ri aniqlash:

function Deko(target: any) { // any — xavfsiz emas, lekin amalda ko'p ishlatiladi
  target.prototype.yangi = true;
}

Xulosa

// Parametrsiz
function Deko(target: Function): void { ... }
@Deko class A {}

// Parametrli (factory)
function Deko(param: string) {
  return (target: Function): void => { ... };
}
@Deko("param") class A {}

// Class qaytarish — kengaytirish
function Deko<T extends new(...a: any[]) => {}>(Base: T) {
  return class extends Base { yangi = true; };
}
@Deko class A {}

Keyingi dars

55-dars: Method dekorator — metodlarni wrapping qilish