O'zbek

Metadata va aspektga yo'naltirilgan dasturlash, shuningdek, deklarativ naqshlar yordamida kodni yaxshilash uchun TypeScript Dekoratorlarining kuchini o'rganing. Jahon dasturchilari uchun to'liq qo'llanma.

TypeScript Dekoratorlari: Mustahkam Ilovalar Uchun Metadata Dasturlash Namunalarini Mukammal O'zlashtirish

Zamonaviy dasturiy ta'minotni ishlab chiqishning keng maydonida toza, kengaytiriladigan va boshqariladigan kod bazalarini saqlash juda muhimdir. TypeScript o'zining kuchli tiplar tizimi va ilg'or xususiyatlari bilan dasturchilarga bunga erishish uchun vositalarni taqdim etadi. Uning eng qiziqarli va transformativ xususiyatlari orasida Dekoratorlar mavjud. Garchi yozish vaqtida hali ham eksperimental xususiyat bo'lsa-da (ECMAScript uchun 3-bosqich taklifi), dekoratorlar Angular va TypeORM kabi freymvorklarda keng qo'llaniladi va bizning dizayn naqshlari, metadata dasturlash va aspektga yo'naltirilgan dasturlashga (AOP) yondashuvimizni tubdan o'zgartiradi.

Ushbu keng qamrovli qo'llanma TypeScript dekoratorlarini chuqur o'rganib chiqadi, ularning mexanikasi, har xil turlari, amaliy qo'llanilishi va eng yaxshi amaliyotlarini o'rganadi. Katta miqyosdagi korporativ ilovalar, mikroxizmatlar yoki mijoz tomonidagi veb-interfeyslarni yaratayotgan bo'lsangiz ham, dekoratorlarni tushunish sizga yanada deklarativ, qo'llab-quvvatlanadigan va kuchli TypeScript kodini yozish imkonini beradi.

Asosiy Kontseptsiyani Tushunish: Dekorator Nima?

Aslida, dekorator - bu sinf e'loni, metod, aksessor, xususiyat yoki parametrga biriktirilishi mumkin bo'lgan maxsus turdagi e'lon. Dekoratorlar o'zlari bezayotgan nishon uchun yangi qiymat qaytaradigan (yoki mavjudini o'zgartiradigan) funksiyalardir. Ularning asosiy maqsadi - asosiy kod tuzilishini to'g'ridan-to'g'ri o'zgartirmasdan, ular biriktirilgan e'longa metadata qo'shish yoki uning xatti-harakatini o'zgartirishdir. Kodni kengaytirishning bu tashqi, deklarativ usuli juda kuchli.

Dekoratorlarni kodingizning qismlariga qo'llaydigan annotatsiyalar yoki yorliqlar deb o'ylang. Keyin bu yorliqlarni ilovangizning boshqa qismlari yoki freymvorklar, ko'pincha ish vaqtida, qo'shimcha funksionallik yoki konfiguratsiyani ta'minlash uchun o'qishi yoki ularga ta'sir qilishi mumkin.

Dekorator Sintaksisi

Dekoratorlar @ belgisi bilan boshlanadi, undan keyin dekorator funksiyasining nomi keladi. Ular bezayotgan e'lonidan darhol oldin joylashtiriladi.

@MyDecorator
class MyClass {
  @AnotherDecorator
  myMethod() {
    // ...
  }
}

TypeScript'da Dekoratorlarni Yoqish

Dekoratorlardan foydalanishdan oldin, tsconfig.json faylingizda experimentalDecorators kompilyator opsiyasini yoqishingiz kerak. Bundan tashqari, ilg'or metadata aks ettirish imkoniyatlari uchun (ko'pincha freymvorklar tomonidan ishlatiladi), sizga emitDecoratorMetadata va reflect-metadata polifili ham kerak bo'ladi.

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2017",
    "module": "commonjs",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

Siz shuningdek reflect-metadata ni o'rnatishingiz kerak:

npm install reflect-metadata --save
# yoki
yarn add reflect-metadata

Va uni ilovangizning kirish nuqtasining eng yuqorisida (masalan, main.ts yoki app.ts) import qiling:

import "reflect-metadata";
// Ilovangiz kodi davom etadi

Dekorator Fabrikalari: Sozlash Sizning Qo'lingizda

Oddiy dekorator funksiya bo'lsa-da, ko'pincha uning xatti-harakatini sozlash uchun dekoratorga argumentlar uzatishingiz kerak bo'ladi. Bunga dekorator fabrikasi yordamida erishiladi. Dekorator fabrikasi - bu haqiqiy dekorator funksiyasini qaytaradigan funksiya. Dekorator fabrikasini qo'llaganingizda, siz uni argumentlari bilan chaqirasiz va u keyin TypeScript kodingizga qo'llaydigan dekorator funksiyasini qaytaradi.

Oddiy Dekorator Fabrikasi Misolini Yaratish

Keling, turli prefikslar bilan xabarlarni qayd etishi mumkin bo'lgan Logger dekoratori uchun fabrika yaratamiz.

function Logger(prefix: string) {
  return function (target: Function) {
    console.log(`[${prefix}] ${target.name} sinfi aniqlandi.`);
  };
}

@Logger("APP_INIT")
class ApplicationBootstrap {
  constructor() {
    console.log("Ilova ishga tushmoqda...");
  }
}

const app = new ApplicationBootstrap();
// Chiqish:
// [APP_INIT] ApplicationBootstrap sinfi aniqlandi.
// Ilova ishga tushmoqda...

Ushbu misolda, Logger("APP_INIT") dekorator fabrikasi chaqiruvidir. U haqiqiy dekorator funksiyasini qaytaradi, bu funksiya argument sifatida target: Function (sinf konstruktori) ni oladi. Bu dekorator xatti-harakatini dinamik ravishda sozlash imkonini beradi.

TypeScript'dagi Dekorator Turlari

TypeScript besh xil dekorator turini qo'llab-quvvatlaydi, ularning har biri ma'lum bir turdagi e'longa qo'llaniladi. Dekorator funksiyasining imzosi u qo'llaniladigan kontekstga qarab o'zgaradi.

1. Sinf Dekoratorlari

Sinf dekoratorlari sinf e'lonlariga qo'llaniladi. Dekorator funksiyasi yagona argument sifatida sinfning konstruktorini oladi. Sinf dekoratori sinf ta'rifini kuzatishi, o'zgartirishi yoki hatto almashtirishi mumkin.

Imzo:

function ClassDecorator(target: Function) { ... }

Qaytariladigan Qiymat:

Agar sinf dekoratori qiymat qaytarsa, u sinf e'lonini taqdim etilgan konstruktor funksiyasi bilan almashtiradi. Bu kuchli xususiyat bo'lib, ko'pincha miksinlar yoki sinfni kengaytirish uchun ishlatiladi. Agar qiymat qaytarilmasa, asl sinf ishlatiladi.

Foydalanish Holatlari:

Sinf Dekoratori Misoli: Xizmatni Kiritish

Sinfni "in'ektsiya qilinadigan" deb belgilash va ixtiyoriy ravishda konteynerda unga nom berishni xohlagan oddiy bog'liqlikni kiritish stsenariysini tasavvur qiling.

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

function Injectable(name?: string) {
  return function<T extends { new(...args: any[]): {} }>(constructor: T) {
    const serviceName = name || constructor.name;
    InjectableServiceRegistry.set(serviceName, constructor);
    console.log(`Ro'yxatdan o'tgan xizmat: ${serviceName}`);

    // Ixtiyoriy ravishda, xatti-harakatni kengaytirish uchun bu yerda yangi sinf qaytarishingiz mumkin
    return class extends constructor {
      createdAt = new Date();
      // Barcha kiritilgan xizmatlar uchun qo'shimcha xususiyatlar yoki metodlar
    };
  };
}

@Injectable("UserService")
class UserDataService {
  getUsers() {
    return [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }];
  }
}

@Injectable()
class ProductDataService {
  getProducts() {
    return [{ id: 101, name: "Laptop" }, { id: 102, name: "Mouse" }];
  }
}

console.log("--- Xizmatlar Ro'yxatdan O'tkazildi ---");
console.log(Array.from(InjectableServiceRegistry.keys()));

const userServiceConstructor = InjectableServiceRegistry.get("UserService");
if (userServiceConstructor) {
  const userServiceInstance = new userServiceConstructor();
  console.log("Foydalanuvchilar:", userServiceInstance.getUsers());
  // console.log("Foydalanuvchi Xizmati Yaratilgan Vaqt:", userServiceInstance.createdAt); // Agar qaytarilgan sinf ishlatilsa
}

Ushbu misol sinf dekoratorining sinfni qanday ro'yxatdan o'tkazishi va hatto uning konstruktorini o'zgartirishi mumkinligini ko'rsatadi. Injectable dekoratori sinfni nazariy bog'liqliklarni kiritish tizimi tomonidan topiladigan qiladi.

2. Metod Dekoratorlari

Metod dekoratorlari metod e'lonlariga qo'llaniladi. Ular uchta argument oladi: nishon obyekti (statik a'zolar uchun konstruktor funksiyasi; instans a'zolari uchun sinf prototipi), metod nomi va metodning xususiyat deskriptori.

Imzo:

function MethodDecorator(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) { ... }

Qaytariladigan Qiymat:

Metod dekoratori yangi PropertyDescriptor qaytarishi mumkin. Agar shunday qilsa, bu deskriptor metodni aniqlash uchun ishlatiladi. Bu sizga asl metodning implementatsiyasini o'zgartirish yoki almashtirish imkonini beradi, bu esa uni AOP uchun juda kuchli qiladi.

Foydalanish Holatlari:

Metod Dekoratori Misoli: Ishlash Samaradorligini Monitoring Qilish

Keling, metodning bajarilish vaqtini qayd etish uchun MeasurePerformance dekoratorini yaratamiz.

function MeasurePerformance(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args: any[]) {
    const start = process.hrtime.bigint();
    const result = originalMethod.apply(this, args);
    const end = process.hrtime.bigint();
    const duration = Number(end - start) / 1_000_000;
    console.log(`"${propertyKey}" metodi ${duration.toFixed(2)} ms ichida bajarildi`);
    return result;
  };

  return descriptor;
}

class DataProcessor {
  @MeasurePerformance
  processData(data: number[]): number[] {
    // Murakkab, vaqt talab qiladigan operatsiyani simulyatsiya qilish
    for (let i = 0; i < 1_000_000; i++) {
      Math.sin(i);
    }
    return data.map(n => n * 2);
  }

  @MeasurePerformance
  fetchRemoteData(id: string): Promise<string> {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(`ID uchun ma'lumotlar: ${id}`);
      }, 500);
    });
  }
}

const processor = new DataProcessor();
processor.processData([1, 2, 3]);
processor.fetchRemoteData("abc").then(result => console.log(result));

MeasurePerformance dekoratori asl metodni vaqtni o'lchash mantiqi bilan o'rab, metod ichidagi biznes mantiqini chalkashtirmasdan bajarilish davomiyligini chop etadi. Bu Aspektga Yo'naltirilgan Dasturlash (AOP)ning klassik namunasidir.

3. Aksessor Dekoratorlari

Aksessor dekoratorlari aksessor (get va set) e'lonlariga qo'llaniladi. Metod dekoratorlariga o'xshab, ular nishon obyekti, aksessor nomi va uning xususiyat deskriptorini oladi.

Imzo:

function AccessorDecorator(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) { ... }

Qaytariladigan Qiymat:

Aksessor dekoratori yangi PropertyDescriptor qaytarishi mumkin, bu aksessorni aniqlash uchun ishlatiladi.

Foydalanish Holatlari:

Aksessor Dekoratori Misoli: Getterlarni Keshlash

Keling, qimmat getter hisob-kitobining natijasini keshlaydigan dekorator yaratamiz.

function CachedGetter(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalGetter = descriptor.get;
  const cacheKey = `_cached_${String(propertyKey)}`;

  if (originalGetter) {
    descriptor.get = function() {
      if (this[cacheKey] === undefined) {
        console.log(`[Kesh Topilmadi] ${String(propertyKey)} uchun qiymat hisoblanmoqda`);
        this[cacheKey] = originalGetter.apply(this);
      } else {
        console.log(`[Kesh Topildi] ${String(propertyKey)} uchun keshlangan qiymat ishlatilmoqda`);
      }
      return this[cacheKey];
    };
  }
  return descriptor;
}

class ReportGenerator {
  private data: number[];

  constructor(data: number[]) {
    this.data = data;
  }

  // Qimmat hisob-kitobni simulyatsiya qiladi
  @CachedGetter
  get expensiveSummary(): number {
    console.log("Qimmat xulosa hisob-kitobi bajarilmoqda...");
    return this.data.reduce((sum, current) => sum + current, 0) / this.data.length;
  }
}

const generator = new ReportGenerator([10, 20, 30, 40, 50]);

console.log("Birinchi kirish:", generator.expensiveSummary);
console.log("Ikkinchi kirish:", generator.expensiveSummary);
console.log("Uchinchi kirish:", generator.expensiveSummary);

Bu dekorator expensiveSummary getter hisob-kitobining faqat bir marta ishlashini ta'minlaydi, keyingi chaqiruvlar keshlangan qiymatni qaytaradi. Bu naqsh xususiyatga kirish og'ir hisob-kitoblar yoki tashqi chaqiruvlarni o'z ichiga olgan hollarda ishlash samaradorligini optimallashtirish uchun juda foydalidir.

4. Xususiyat Dekoratorlari

Xususiyat dekoratorlari xususiyat e'lonlariga qo'llaniladi. Ular ikkita argument oladi: nishon obyekti (statik a'zolar uchun konstruktor funksiyasi; instans a'zolari uchun sinf prototipi) va xususiyat nomi.

Imzo:

function PropertyDecorator(target: Object, propertyKey: string | symbol) { ... }

Qaytariladigan Qiymat:

Xususiyat dekoratorlari hech qanday qiymat qaytara olmaydi. Ularning asosiy vazifasi xususiyat haqida metadata ro'yxatdan o'tkazishdir. Ular dekoratsiya vaqtida xususiyatning qiymatini yoki uning deskriptorini to'g'ridan-to'g'ri o'zgartira olmaydi, chunki xususiyat dekoratorlari ishlaganda xususiyat uchun deskriptor hali to'liq aniqlanmagan bo'ladi.

Foydalanish Holatlari:

Xususiyat Dekoratori Misoli: Majburiy Maydonni Tekshirish

Keling, xususiyatni "majburiy" deb belgilash va keyin uni ish vaqtida tekshirish uchun dekorator yaratamiz.

interface ValidationRule {
  property: string | symbol;
  validate: (value: any) => boolean;
  message: string;
}

const validationRules: Map<Function, ValidationRule[]> = new Map();

function Required(target: Object, propertyKey: string | symbol) {
  const rules = validationRules.get(target.constructor) || [];
  rules.push({
    property: propertyKey,
    validate: (value: any) => value !== null && value !== undefined && value !== "",
    message: `${String(propertyKey)} majburiy.`
  });
  validationRules.set(target.constructor, rules);
}

function validate(instance: any): string[] {
  const classRules = validationRules.get(instance.constructor) || [];
  const errors: string[] = [];

  for (const rule of classRules) {
    if (!rule.validate(instance[rule.property])) {
      errors.push(rule.message);
    }
  }
  return errors;
}

class UserProfile {
  @Required
  firstName: string;

  @Required
  lastName: string;

  age?: number;

  constructor(firstName: string, lastName: string, age?: number) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }
}

const user1 = new UserProfile("John", "Doe", 30);
console.log("User 1 tekshiruv xatolari:", validate(user1)); // []

const user2 = new UserProfile("", "Smith");
console.log("User 2 tekshiruv xatolari:", validate(user2)); // ["firstName majburiy."]

const user3 = new UserProfile("Alice", "");
console.log("User 3 tekshiruv xatolari:", validate(user3)); // ["lastName majburiy."]

Required dekoratori shunchaki tekshirish qoidasini markaziy validationRules xaritasida ro'yxatdan o'tkazadi. Keyin alohida validate funksiyasi ish vaqtida instansni tekshirish uchun ushbu metadatadan foydalanadi. Bu naqsh tekshirish mantiqini ma'lumotlar ta'rifidan ajratadi, bu uni qayta ishlatiladigan va toza qiladi.

5. Parametr Dekoratorlari

Parametr dekoratorlari sinf konstruktori yoki metod ichidagi parametrlarga qo'llaniladi. Ular uchta argument oladi: nishon obyekti (statik a'zolar uchun konstruktor funksiyasi; instans a'zolari uchun sinf prototipi), metod nomi (yoki konstruktor parametrlari uchun undefined) va funksiyaning parametrlar ro'yxatidagi parametrning tartib indeksi.

Imzo:

function ParameterDecorator(target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) { ... }

Qaytariladigan Qiymat:

Parametr dekoratorlari hech qanday qiymat qaytara olmaydi. Xususiyat dekoratorlari kabi, ularning asosiy roli parametr haqida metadata qo'shishdir.

Foydalanish Holatlari:

Parametr Dekoratori Misoli: So'rov Ma'lumotlarini Kiritish

Keling, veb-freymvorkning metod parametriga ma'lum ma'lumotlarni, masalan, so'rovdan foydalanuvchi ID'sini kiritish uchun parametr dekoratorlaridan qanday foydalanishi mumkinligini simulyatsiya qilamiz.

interface ParameterMetadata {
  index: number;
  key: string | symbol;
  resolver: (request: any) => any;
}

const parameterResolvers: Map<Function, Map<string | symbol, ParameterMetadata[]>> = new Map();

function RequestParam(paramName: string) {
  return function (target: Object, propertyKey: string | symbol | undefined, parameterIndex: number) {
    const targetKey = propertyKey || "constructor";
    let methodResolvers = parameterResolvers.get(target.constructor);
    if (!methodResolvers) {
      methodResolvers = new Map();
      parameterResolvers.set(target.constructor, methodResolvers);
    }
    const paramMetadata = methodResolvers.get(targetKey) || [];
    paramMetadata.push({
      index: parameterIndex,
      key: targetKey,
      resolver: (request: any) => request[paramName]
    });
    methodResolvers.set(targetKey, paramMetadata);
  };
}

// Metodni hal qilingan parametrlar bilan chaqirish uchun gipotetik freymvork funksiyasi
function executeWithParams(instance: any, methodName: string, request: any) {
  const classResolvers = parameterResolvers.get(instance.constructor);
  if (!classResolvers) {
    return (instance[methodName] as Function).apply(instance, []);
  }
  const methodParamMetadata = classResolvers.get(methodName);
  if (!methodParamMetadata) {
    return (instance[methodName] as Function).apply(instance, []);
  }

  const args: any[] = Array(methodParamMetadata.length);
  for (const meta of methodParamMetadata) {
    args[meta.index] = meta.resolver(request);
  }
  return (instance[methodName] as Function).apply(instance, args);
}

class UserController {
  getUser(@RequestParam("id") userId: string, @RequestParam("token") authToken?: string) {
    console.log(`Foydalanuvchini ID bilan qidirish: ${userId}, Token: ${authToken || "N/A"}`);
    return { id: userId, name: "Jane Doe" };
  }

  deleteUser(@RequestParam("id") userId: string) {
    console.log(`Foydalanuvchini ID bilan o'chirish: ${userId}`);
    return { status: "deleted", id: userId };
  }
}

const userController = new UserController();

// Kiruvchi so'rovni simulyatsiya qilish
const mockRequest = {
  id: "user123",
  token: "abc-123",
  someOtherProp: "xyz"
};

console.log("\n--- getUser bajarilmoqda ---");
executeWithParams(userController, "getUser", mockRequest);

console.log("\n--- deleteUser bajarilmoqda ---");
executeWithParams(userController, "deleteUser", { id: "user456" });

Ushbu misol parametr dekoratorlarining talab qilinadigan metod parametrlari haqida qanday ma'lumot to'plashi mumkinligini ko'rsatadi. Keyin freymvork ushbu to'plangan metadatadan foydalanib, metod chaqirilganda tegishli qiymatlarni avtomatik ravishda hal qilishi va kiritishi mumkin, bu esa kontroller yoki xizmat mantiqini sezilarli darajada soddalashtiradi.

Dekorator Kompozitsiyasi va Bajarilish Tartibi

Dekoratorlar turli kombinatsiyalarda qo'llanilishi mumkin va ularning bajarilish tartibini tushunish xatti-harakatni bashorat qilish va kutilmagan muammolardan qochish uchun juda muhimdir.

Yagona Nishonga Bir Nechta Dekoratorlar

Bir e'longa (masalan, sinf, metod yoki xususiyat) bir nechta dekorator qo'llanilganda, ular baholash uchun ma'lum bir tartibda ishlaydi: pastdan yuqoriga yoki o'ngdan chapga. Biroq, ularning natijalari teskari tartibda qo'llaniladi.

@DecoratorA
@DecoratorB
class MyClass {
  // ...
}

Bu yerda avval DecoratorB baholanadi, keyin DecoratorA. Agar ular sinfni o'zgartirsa (masalan, yangi konstruktor qaytarish orqali), DecoratorA dan o'zgartirish DecoratorB dan o'zgartirishni o'rab oladi yoki uning ustiga qo'llaniladi.

Misol: Metod Dekoratorlarini Zanjir Qilish

Ikkita metod dekoratorini ko'rib chiqaylik: LogCall va Authorization.

function LogCall(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`[LOG] ${String(propertyKey)} chaqirilmoqda, argumentlar:`, args);
    const result = originalMethod.apply(this, args);
    console.log(`[LOG] ${String(propertyKey)} metodi qaytardi:`, result);
    return result;
  };
  return descriptor;
}

function Authorization(roles: string[]) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
      const currentUserRoles = ["admin"]; // Joriy foydalanuvchi rollarini olishni simulyatsiya qilish
      const authorized = roles.some(role => currentUserRoles.includes(role));
      if (!authorized) {
        console.warn(`[AUTH] ${String(propertyKey)} uchun kirish rad etildi. Talab qilinadigan rollar: ${roles.join(", ")}`);
        throw new Error("Ruxsatsiz kirish");
      }
      console.log(`[AUTH] ${String(propertyKey)} uchun kirishga ruxsat berildi`);
      return originalMethod.apply(this, args);
    };
    return descriptor;
  };
}

class SecureService {
  @LogCall
  @Authorization(["admin"])
  deleteSensitiveData(id: string) {
    console.log(`Maxfiy ma'lumotlar o'chirilmoqda, ID: ${id}`);
    return `Ma'lumot ID ${id} o'chirildi.`;
  }

  @Authorization(["user"])
  @LogCall // Tartib bu yerda o'zgartirildi
  fetchPublicData(query: string) {
    console.log(`Ommaviy ma'lumotlar so'rov bilan qidirilmoqda: ${query}`);
    return `So'rov uchun ommaviy ma'lumotlar: ${query}`; 
  }
}

const service = new SecureService();

try {
  console.log("\n--- deleteSensitiveData (Admin Foydalanuvchi) chaqirilmoqda ---");
  service.deleteSensitiveData("record123");
} catch (error: any) {
  console.error(error.message);
}

try {
  console.log("\n--- fetchPublicData (Admin bo'lmagan Foydalanuvchi) chaqirilmoqda ---");
  // 'user' rolini talab qiladigan fetchPublicData ga kirishga urinayotgan admin bo'lmagan foydalanuvchini simulyatsiya qilish
  const mockUserRoles = ["guest"]; // Bu avtorizatsiyadan o'tmaydi
  // Buni dinamik qilish uchun sizga DI tizimi yoki joriy foydalanuvchi rollari uchun statik kontekst kerak bo'ladi.
  // Sodda bo'lishi uchun, Authorization dekoratori joriy foydalanuvchi kontekstiga kirish huquqiga ega deb faraz qilamiz.
  // Birinchi chaqiruv muvaffaqiyatli bo'lishi va ikkinchisi muvaffaqiyatsiz bo'lishi uchun demo maqsadida Authorization dekoratorini har doim 'admin' deb hisoblashga sozlaymiz,
  // shunda turli yo'llar ko'rsatiladi.
  
  // fetchPublicData muvaffaqiyatli bo'lishi uchun foydalanuvchi roli bilan qayta ishga tushiring.
  // Authorization'dagi currentUserRoles: ['user'] bo'ladi deb tasavvur qiling
  // Ushbu misol uchun, buni oddiy saqlaymiz va tartib ta'sirini ko'rsatamiz.
  service.fetchPublicData("search term"); // Bu Auth -> Log ni bajaradi
} catch (error: any) {
  console.error(error.message);
}

/* deleteSensitiveData uchun kutilgan chiqish:
[AUTH] deleteSensitiveData uchun kirishga ruxsat berildi
[LOG] deleteSensitiveData chaqirilmoqda, argumentlar: [ 'record123' ]
Maxfiy ma'lumotlar o'chirilmoqda, ID: record123
[LOG] deleteSensitiveData metodi qaytardi: Ma'lumot ID record123 o'chirildi.
*/

/* fetchPublicData uchun kutilgan chiqish (agar foydalanuvchi 'user' roliga ega bo'lsa):
[LOG] fetchPublicData chaqirilmoqda, argumentlar: [ 'search term' ]
[AUTH] fetchPublicData uchun kirishga ruxsat berildi
Ommaviy ma'lumotlar so'rov bilan qidirilmoqda: search term
[LOG] fetchPublicData metodi qaytardi: So'rov uchun ommaviy ma'lumotlar: search term
*/

Tartibga e'tibor bering: deleteSensitiveData uchun avval Authorization (pastdagi) ishlaydi, keyin LogCall (yuqoridagi) uni o'rab oladi. Authorization ichki mantiqi birinchi bajariladi. fetchPublicData uchun avval LogCall (pastdagi) ishlaydi, keyin Authorization (yuqoridagi) uni o'rab oladi. Bu LogCall aspekti Authorization aspektidan tashqarida bo'lishini anglatadi. Bu farq kesib o'tuvchi masalalar, masalan, loglash yoki xatoliklarni qayta ishlash uchun muhimdir, bu yerda bajarilish tartibi xatti-harakatga sezilarli ta'sir qilishi mumkin.

Turli Nishonlar Uchun Bajarilish Tartibi

Sinf, uning a'zolari va parametrlarining barchasi dekoratorlarga ega bo'lganda, bajarilish tartibi aniq belgilangan:

  1. Parametr Dekoratorlari birinchi bo'lib har bir parametr uchun, oxirgi parametrdan birinchisiga qarab qo'llaniladi.
  2. Keyin, Metod, Aksessor yoki Xususiyat Dekoratorlari har bir a'zo uchun qo'llaniladi.
  3. Nihoyat, Sinf Dekoratorlari sinfning o'ziga qo'llaniladi.

Har bir kategoriya ichida, bir xil nishondagi bir nechta dekoratorlar pastdan yuqoriga (yoki o'ngdan chapga) qo'llaniladi.

Misol: To'liq Bajarilish Tartibi

function log(message: string) {
  return function (target: any, propertyKey: string | symbol | undefined, descriptorOrIndex?: PropertyDescriptor | number) {
    if (typeof descriptorOrIndex === 'number') {
      console.log(`Parametr Dekoratori: ${message} ${String(propertyKey || "constructor")} ning #${descriptorOrIndex} parametrida`);
    } else if (typeof propertyKey === 'string' || typeof propertyKey === 'symbol') {
      if (descriptorOrIndex && 'value' in descriptorOrIndex && typeof descriptorOrIndex.value === 'function') {
        console.log(`Metod/Aksessor Dekoratori: ${message} ${String(propertyKey)} da`);
      } else {
        console.log(`Xususiyat Dekoratori: ${message} ${String(propertyKey)} da`);
      }
    } else {
      console.log(`Sinf Dekoratori: ${message} ${target.name} da`);
    }
    return descriptorOrIndex; // Metod/aksessor uchun deskriptorni, boshqalar uchun undefined qaytaradi
  };
}

@log("Sinf Darajasi D")
@log("Sinf Darajasi C")
class MyDecoratedClass {
  @log("Statik Xususiyat A")
  static staticProp: string = "";

  @log("Instans Xususiyati B")
  instanceProp: number = 0;

  @log("Metod D")
  @log("Metod C")
  myMethod(
    @log("Parametr Z") paramZ: string,
    @log("Parametr Y") paramY: number
  ) {
    console.log("myMethod metodi bajarildi.");
  }

  @log("Getter/Setter F")
  get myAccessor() {
    return "";
  }

  set myAccessor(value: string) {
    //...
  }

  constructor() {
    console.log("Konstruktor bajarildi.");
  }
}

new MyDecoratedClass();
// Metod dekoratorini ishga tushirish uchun metodni chaqirish
new MyDecoratedClass().myMethod("hello", 123);

/* Taxminiy Chiqish Tartibi (muayyan TypeScript versiyasi va kompilyatsiyaga bog'liq):
Parametr Dekoratori: Parametr Y myMethod ning #1 parametrida
Parametr Dekoratori: Parametr Z myMethod ning #0 parametrida
Xususiyat Dekoratori: Statik Xususiyat A staticProp da
Xususiyat Dekoratori: Instans Xususiyati B instanceProp da
Metod/Aksessor Dekoratori: Getter/Setter F myAccessor da
Metod/Aksessor Dekoratori: Metod C myMethod da
Metod/Aksessor Dekoratori: Metod D myMethod da
Sinf Dekoratori: Sinf Darajasi C MyDecoratedClass da
Sinf Dekoratori: Sinf Darajasi D MyDecoratedClass da
Konstruktor bajarildi.
myMethod metodi bajarildi.
*/

Aniq konsolga yozish vaqti konstruktor yoki metod qachon chaqirilishiga qarab biroz o'zgarishi mumkin, ammo dekorator funksiyalarining o'zlari bajarilish tartibi (va shuning uchun ularning yon ta'sirlari yoki qaytarilgan qiymatlari qo'llanilishi) yuqoridagi qoidalarga amal qiladi.

Dekoratorlar Bilan Amaliy Qo'llashlar va Dizayn Namunalar

Dekoratorlar, ayniqsa reflect-metadata polifili bilan birgalikda, metadata asosidagi dasturlashning yangi sohasini ochib beradi. Bu shablon kodni va kesib o'tuvchi masalalarni abstrakt qiladigan kuchli dizayn namunalariga imkon beradi.

1. Bog'liqliklarni Kiritish (DI)

Dekoratorlarning eng mashhur qo'llanilishidan biri Bog'liqliklarni Kiritish freymvorklarida (masalan, Angular'ning @Injectable(), @Component() va boshqalar yoki NestJS'ning DI'dan keng foydalanishi). Dekoratorlar sizga bog'liqliklarni to'g'ridan-to'g'ri konstruktorlar yoki xususiyatlarda e'lon qilish imkonini beradi, bu esa freymvorkka to'g'ri xizmatlarni avtomatik ravishda yaratish va taqdim etish imkonini beradi.

Misol: Soddalashtirilgan Xizmatni Kiritish

import "reflect-metadata"; // emitDecoratorMetadata uchun muhim

const INJECTABLE_METADATA_KEY = Symbol("injectable");
const INJECT_METADATA_KEY = Symbol("inject");

function Injectable() {
  return function (target: Function) {
    Reflect.defineMetadata(INJECTABLE_METADATA_KEY, true, target);
  };
}

function Inject(token: any) {
  return function (target: Object, propertyKey: string | symbol, parameterIndex: number) {
    const existingInjections: any[] = Reflect.getOwnMetadata(INJECT_METADATA_KEY, target, propertyKey) || [];
    existingInjections[parameterIndex] = token;
    Reflect.defineMetadata(INJECT_METADATA_KEY, existingInjections, target, propertyKey);
  };
}

class Container {
  private static instances = new Map<any, any>();

  static resolve<T>(target: { new (...args: any[]): T }): T {
    if (Container.instances.has(target)) {
      return Container.instances.get(target);
    }

    const isInjectable = Reflect.getMetadata(INJECTABLE_METADATA_KEY, target);
    if (!isInjectable) {
      throw new Error(`${target.name} sinfi @Injectable deb belgilanmagan.`);
    }

    // Konstruktor parametrlarining turlarini olish (emitDecoratorMetadata talab qiladi)
    const paramTypes: any[] = Reflect.getMetadata("design:paramtypes", target) || [];
    const explicitInjections: any[] = Reflect.getMetadata(INJECT_METADATA_KEY, target) || [];

    const dependencies = paramTypes.map((paramType, index) => {
      // Agar taqdim etilgan bo'lsa, aniq @Inject tokenidan foydalaning, aks holda tipni aniqlang
      const token = explicitInjections[index] || paramType;
      if (token === undefined) {
        throw new Error(`${target.name} uchun ${index} indeksidagi parametrni hal qilib bo'lmadi. Bu aylanma bog'liqlik yoki aniq @Inject'siz primitiv tur bo'lishi mumkin.`);
      }
      return Container.resolve(token);
    });

    const instance = new target(...dependencies);
    Container.instances.set(target, instance);
    return instance;
  }
}

// Xizmatlarni aniqlash
@Injectable()
class DatabaseService {
  connect() {
    console.log("Ma'lumotlar bazasiga ulanilmoqda...");
    return "DB Ulanishi";
  }
}

@Injectable()
class AuthService {
  private db: DatabaseService;

  constructor(db: DatabaseService) {
    this.db = db;
  }

  login() {
    console.log(`AuthService: ${this.db.connect()} yordamida autentifikatsiya qilinmoqda`);
    return "Foydalanuvchi tizimga kirdi";
  }
}

@Injectable()
class UserService {
  private authService: AuthService;
  private dbService: DatabaseService; // Maxsus dekorator yoki freymvork xususiyati yordamida xususiyat orqali kiritish misoli

  constructor(@Inject(AuthService) authService: AuthService,
              @Inject(DatabaseService) dbService: DatabaseService) {
    this.authService = authService;
    this.dbService = dbService;
  }

  getUserProfile() {
    this.authService.login();
    this.dbService.connect();
    console.log("UserService: Foydalanuvchi profilini qidirilmoqda...");
    return { id: 1, name: "Global User" };
  }
}

// Asosiy xizmatni hal qilish
console.log("--- UserService hal qilinmoqda ---");
const userService = Container.resolve(UserService);
console.log(userService.getUserProfile());

console.log("\n--- AuthService hal qilinmoqda (keshlangan bo'lishi kerak) ---");
const authService = Container.resolve(AuthService);
authService.login();

Ushbu murakkab misol @Injectable va @Inject dekoratorlarining reflect-metadata bilan birgalikda maxsus Container ga bog'liqliklarni avtomatik ravishda hal qilish va taqdim etish imkonini berishini ko'rsatadi. TypeScript tomonidan avtomatik ravishda chiqariladigan design:paramtypes metadatasi (emitDecoratorMetadata rost bo'lganda) bu yerda juda muhimdir.

2. Aspektga Yo'naltirilgan Dasturlash (AOP)

AOP bir nechta sinf va modullarni kesib o'tadigan kesib o'tuvchi masalalarni (masalan, loglash, xavfsizlik, tranzaktsiyalar) modullashtirishga qaratilgan. Dekoratorlar TypeScript'da AOP kontseptsiyalarini amalga oshirish uchun ajoyib mos keladi.

Misol: Metod Dekoratori Bilan Loglash

LogCall dekoratoriga qaytsak, bu AOPning mukammal namunasidir. U metodning asl kodini o'zgartirmasdan har qanday metodga loglash xatti-harakatini qo'shadi. Bu "nima qilish kerak" (biznes mantiqi) ni "qanday qilish kerak" (loglash, ishlash monitoringi va h.k.) dan ajratadi.

function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`[LOG AOP] Metodga kirilmoqda: ${String(propertyKey)}, argumentlar:`, args);
    try {
      const result = originalMethod.apply(this, args);
      console.log(`[LOG AOP] Metoddan chiqilmoqda: ${String(propertyKey)}, natija:`, result);
      return result;
    } catch (error: any) {
      console.error(`[LOG AOP] ${String(propertyKey)} metodida xatolik:`, error.message);
      throw error;
    }
  };
  return descriptor;
}

class PaymentProcessor {
  @LogMethod
  processPayment(amount: number, currency: string) {
    if (amount <= 0) {
      throw new Error("To'lov miqdori musbat bo'lishi kerak.");
    }
    console.log(`${amount} ${currency} to'lovi qayta ishlanmoqda...`);
    return `${amount} ${currency} to'lovi muvaffaqiyatli qayta ishlandi.`;
  }

  @LogMethod
  refundPayment(transactionId: string) {
    console.log(`Tranzaksiya ID si uchun to'lov qaytarilmoqda: ${transactionId}...`);
    return `${transactionId} uchun qaytarish boshlandi.`;
  }
}

const processor = new PaymentProcessor();
processor.processPayment(100, "USD");
try {
  processor.processPayment(-50, "EUR");
} catch (error: any) {
  console.error("Ushlangan xato:", error.message);
}

Ushbu yondashuv PaymentProcessor sinfini faqat to'lov mantiqiga qaratilgan holda saqlaydi, LogMethod dekoratori esa loglashning kesib o'tuvchi masalasini hal qiladi.

3. Tekshirish va Transformatsiya

Dekoratorlar xususiyatlarda tekshirish qoidalarini to'g'ridan-to'g'ri aniqlash yoki seriyalash/deserializatsiya paytida ma'lumotlarni o'zgartirish uchun juda foydalidir.

Misol: Xususiyat Dekoratorlari Bilan Ma'lumotlarni Tekshirish

Yuqoridagi @Required misoli buni allaqachon ko'rsatgan edi. Mana sonli diapazonni tekshirish bilan yana bir misol.

interface FieldValidationRule {
  property: string | symbol;
  validator: (value: any) => boolean;
  message: string;
}

const fieldValidationRules = new Map<Function, FieldValidationRule[]>();

function addValidationRule(target: Object, propertyKey: string | symbol, validator: (value: any) => boolean, message: string) {
  const rules = fieldValidationRules.get(target.constructor) || [];
  rules.push({ property: propertyKey, validator, message });
  fieldValidationRules.set(target.constructor, rules);
}

function IsPositive(target: Object, propertyKey: string | symbol) {
  addValidationRule(target, propertyKey, (value: number) => value > 0, `${String(propertyKey)} musbat son bo'lishi kerak.`);
}

function MaxLength(maxLength: number) {
  return function (target: Object, propertyKey: string | symbol) {
    addValidationRule(target, propertyKey, (value: string) => value.length <= maxLength, `${String(propertyKey)} ko'pi bilan ${maxLength} belgidan iborat bo'lishi kerak.`);
  };
}

class Product {
  @MaxLength(50)
  name: string;

  @IsPositive
  price: number;

  constructor(name: string, price: number) {
    this.name = name;
    this.price = price;
  }

  static validate(instance: any): string[] {
    const errors: string[] = [];
    const rules = fieldValidationRules.get(instance.constructor) || [];
    for (const rule of rules) {
      if (!rule.validator(instance[rule.property])) {
        errors.push(rule.message);
      }
    }
    return errors;
  }
}

const product1 = new Product("Laptop", 1200);
console.log("Mahsulot 1 xatolari:", Product.validate(product1)); // []

const product2 = new Product("Juda uzun mahsulot nomi, sinov maqsadi uchun ellik belgi chegarasidan oshadi", 50);
console.log("Mahsulot 2 xatolari:", Product.validate(product2)); // ["name ko'pi bilan 50 belgidan iborat bo'lishi kerak."]

const product3 = new Product("Kitob", -10);
console.log("Mahsulot 3 xatolari:", Product.validate(product3)); // ["price musbat son bo'lishi kerak."]

Ushbu sozlama sizga model xususiyatlarida tekshirish qoidalarini deklarativ ravishda aniqlash imkonini beradi, bu esa ma'lumotlar modellaringizni ularning cheklovlari nuqtai nazaridan o'z-o'zini tavsiflovchi qiladi.

Eng Yaxshi Amaliyotlar va Mulohazalar

Dekoratorlar kuchli bo'lsa-da, ularni oqilona ishlatish kerak. Ularni noto'g'ri ishlatish disk raskadrovka qilish yoki tushunish qiyin bo'lgan kodga olib kelishi mumkin.

Dekoratorlarni Qachon Ishlatish Kerak (va Qachon Ishlatmaslik Kerak)

Ishlash Samaradorligiga Ta'siri

Dekoratorlar kompilyatsiya vaqtida (yoki transpilatsiya qilingan JavaScript ish vaqtida aniqlash vaqtida) bajariladi. Transformatsiya yoki metadata to'plami sinf/metod aniqlanganda sodir bo'ladi, har bir chaqiruvda emas. Shuning uchun, dekoratorlarni *qo'llash*ning ish vaqtidagi ishlash samaradorligiga ta'siri minimaldir. Biroq, dekoratorlaringiz *ichidagi mantiq* ishlash samaradorligiga ta'sir qilishi mumkin, ayniqsa ular har bir metod chaqiruvida qimmat operatsiyalarni bajarsa (masalan, metod dekoratori ichidagi murakkab hisob-kitoblar).

Qo'llab-quvvatlanuvchanlik va O'qiluvchanlik

Dekoratorlar, to'g'ri ishlatilganda, shablon kodni asosiy mantiqdan tashqariga chiqarib, o'qiluvchanlikni sezilarli darajada yaxshilashi mumkin. Biroq, agar ular murakkab, yashirin transformatsiyalarni bajarsa, disk raskadrovka qilish qiyinlashishi mumkin. Dekoratorlaringiz yaxshi hujjatlashtirilganligiga va ularning xatti-harakati bashorat qilinadigan bo'lishiga ishonch hosil qiling.

Eksperimental Holat va Dekoratorlarning Kelajagi

TypeScript dekoratorlari TC39 ning 3-bosqich taklifiga asoslanganligini yana bir bor ta'kidlash muhim. Bu spetsifikatsiya asosan barqaror, ammo rasmiy ECMAScript standartining bir qismi bo'lishidan oldin hali ham kichik o'zgarishlarga duch kelishi mumkinligini anglatadi. Angular kabi freymvorklar ularni qabul qilib, ularning oxir-oqibat standartlashishiga ishongan. Bu ma'lum darajadagi xavfni anglatadi, ammo ularning keng tarqalganligini hisobga olsak, sezilarli buzuvchi o'zgarishlar ehtimoldan yiroq emas.

TC39 taklifi rivojlandi. TypeScript'ning joriy implementatsiyasi taklifning eski versiyasiga asoslangan. "Eski Dekoratorlar" va "Standart Dekoratorlar" o'rtasida farq bor. Rasmiy standart chiqqanda, TypeScript o'zining implementatsiyasini yangilashi mumkin. Ko'pgina freymvorklardan foydalanadigan dasturchilar uchun bu o'tish freymvorkning o'zi tomonidan boshqariladi. Kutubxona mualliflari uchun eski va kelajakdagi standart dekoratorlar o'rtasidagi nozik farqlarni tushunish zarur bo'lishi mumkin.

emitDecoratorMetadata Kompilyator Opsiyasi

Ushbu parametr tsconfig.json da true ga o'rnatilganda, TypeScript kompilyatoriga ma'lum dizayn vaqtidagi tip metadatasini kompilyatsiya qilingan JavaScript'ga chiqarishni buyuradi. Bu metadata konstruktor parametrlarining turini (design:paramtypes), metodlarning qaytarish turini (design:returntype) va xususiyatlarning turini (design:type) o'z ichiga oladi.

Ushbu chiqarilgan metadata standart JavaScript ish vaqtining bir qismi emas. Odatda uni reflect-metadata polifili iste'mol qiladi, keyin esa uni Reflect.getMetadata() funksiyalari orqali kirish mumkin qiladi. Bu Bog'liqliklarni Kiritish kabi ilg'or naqshlar uchun mutlaqo zarurdir, bu yerda konteyner sinf talab qiladigan bog'liqliklar turlarini aniq konfiguratsiyasiz bilishi kerak.

Dekoratorlar Bilan Ilg'or Naqshlar

Dekoratorlarni birlashtirib va kengaytirib, yanada murakkab naqshlar yaratish mumkin.

1. Dekoratorlarni Dekoratsiya Qilish (Yuqori Tartibli Dekoratorlar)

Siz boshqa dekoratorlarni o'zgartiradigan yoki tashkil etadigan dekoratorlar yaratishingiz mumkin. Bu kamroq uchraydi, lekin dekoratorlarning funktsional tabiatini namoyish etadi.

// Metodning loglanishini va admin rollarini talab qilishini ta'minlaydigan dekorator
function AdminAndLoggedMethod() {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    // Avval Authorization'ni qo'llang (ichki)
    Authorization(["admin"])(target, propertyKey, descriptor);
    // Keyin LogCall'ni qo'llang (tashqi)
    LogCall(target, propertyKey, descriptor);

    return descriptor; // O'zgartirilgan deskriptorni qaytaring
  };
}

class AdminPanel {
  @AdminAndLoggedMethod()
  deleteUserAccount(userId: string) {
    console.log(`Foydalanuvchi hisobi o'chirilmoqda: ${userId}`);
    return `Foydalanuvchi ${userId} o'chirildi.`;
  }
}

const adminPanel = new AdminPanel();
adminPanel.deleteUserAccount("user007");
/* Kutilgan Chiqish (admin roli mavjud deb taxmin qilinsa):
[AUTH] deleteUserAccount uchun kirishga ruxsat berildi
[LOG] deleteUserAccount chaqirilmoqda, argumentlar: [ 'user007' ]
Foydalanuvchi hisobi o'chirilmoqda: user007
[LOG] deleteUserAccount metodi qaytardi: Foydalanuvchi user007 o'chirildi.
*/

Bu yerda, AdminAndLoggedMethod dekorator qaytaradigan fabrika bo'lib, o'sha dekorator ichida u boshqa ikkita dekoratorni qo'llaydi. Bu naqsh murakkab dekorator kompozitsiyalarini qamrab olishi mumkin.

2. Miksinlar Uchun Dekoratorlardan Foydalanish

TypeScript miksinlarni amalga oshirishning boshqa usullarini taklif qilsa-da, dekoratorlardan sinflarga qobiliyatlarni deklarativ tarzda kiritish uchun foydalanish mumkin.

function ApplyMixins(constructors: Function[]) {
  return function (derivedConstructor: Function) {
    constructors.forEach(baseConstructor => {
      Object.getOwnPropertyNames(baseConstructor.prototype).forEach(name => {
        Object.defineProperty(
          derivedConstructor.prototype,
          name,
          Object.getOwnPropertyDescriptor(baseConstructor.prototype, name) || Object.create(null)
        );
      });
    });
  };
}

class Disposable {
  isDisposed: boolean = false;
  dispose() {
    this.isDisposed = true;
    console.log("Obyekt yo'q qilindi.");
  }
}

class Loggable {
  log(message: string) {
    console.log(`[Loggable] ${message}`);
  }
}

@ApplyMixins([Disposable, Loggable])
class MyResource implements Disposable, Loggable {
  // Bu xususiyatlar/metodlar dekorator tomonidan kiritiladi
  isDisposed!: boolean;
  dispose!: () => void;
  log!: (message: string) => void;

  constructor(public name: string) {
    this.log(`Resurs ${this.name} yaratildi.`);
  }

  cleanUp() {
    this.dispose();
    this.log(`Resurs ${this.name} tozalandi.`);
  }
}

const resource = new MyResource("NetworkConnection");
console.log(`Yo'q qilinganmi: ${resource.isDisposed}`);
resource.cleanUp();
console.log(`Yo'q qilinganmi: ${resource.isDisposed}`);

Ushbu @ApplyMixins dekoratori metodlar va xususiyatlarni asos konstruktorlardan hosilaviy sinfning prototipiga dinamik ravishda nusxalaydi, bu esa funksionalliklarni samarali "aralashtirib yuboradi".

Xulosa: Zamonaviy TypeScript Dasturlashni Kuchaytirish

TypeScript dekoratorlari metadata asosidagi va aspektga yo'naltirilgan dasturlashning yangi paradigmasini yaratishga imkon beruvchi kuchli va ifodali xususiyatdir. Ular dasturchilarga sinflar, metodlar, xususiyatlar, aksessorlar va parametrlarga ularning asosiy mantiqini o'zgartirmasdan deklarativ xatti-harakatlarni yaxshilash, o'zgartirish va qo'shish imkonini beradi. Mas'uliyatlarni bu tarzda ajratish toza, qo'llab-quvvatlanuvchan va yuqori darajada qayta ishlatiladigan kodga olib keladi.

Bog'liqliklarni kiritishni soddalashtirish va mustahkam tekshirish tizimlarini amalga oshirishdan tortib, loglash va ishlash monitoringi kabi kesib o'tuvchi masalalarni qo'shishgacha, dekoratorlar ko'plab umumiy dasturlash muammolariga nafis yechim taklif qiladi. Ularning eksperimental maqomi ehtiyotkorlikni talab qilsa-da, yirik freymvorklarda keng tarqalganligi ularning amaliy ahamiyati va kelajakdagi dolzarbligini bildiradi.

TypeScript dekoratorlarini mukammal o'zlashtirib, siz o'z arsenalingizda muhim vositaga ega bo'lasiz, bu sizga yanada mustahkam, kengaytiriladigan va aqlli ilovalar yaratish imkonini beradi. Ularni mas'uliyat bilan qabul qiling, ularning mexanikasini tushuning va TypeScript loyihalaringizda deklarativ kuchning yangi darajasini oching.