WisarWisar
Dasturlash kitobi/8-QISM — NestJS29 daqiqa

8.2-bob: Dependency Injection (chuqur)

8-QISM — NestJS (chuqur) · 2-mavzu


1. Kirish va motivatsiya

8.1-bobda NestJS arxitekturasini va dependency injection (DI) ni qisqacha ko'rdik. Endi uni — NestJS'ning eng muhim, eng kuchli, butun sehrining asosi bo'lgan mexanizmni — chuqur o'rganamiz. DI'ni tushunmasdan NestJS'ni "ishlataman" deyish mumkin, lekin uni bilaman deb bo'lmaydi. Bu bob — sizning NestJS bilimingizning poydevori (8.1'da boshladik; bu yerda to'liq, ichki ishlash bilan).

Dependency Injection — "bog'liqlikni kiritish" — class o'ziga kerakli bog'liqliklarni (boshqa service, DB, config) o'zi yaratmaydi, balki tashqaridan oladi (constructor orqali). NestJS'da bu — IoC konteyner (Inversion of Control — nazoratning teskari aylanishi) tomonidan avtomatik qilinadi. Siz constructor(private service: UserService) {} deysiz — NestJS UserServiceni (va uning barcha bog'liqliklarini) o'zi yaratib, ulab beradi. Bu — sehirdek ko'rinadi, lekin aniq, mantiqiy mexanizm (TS turlari + reflect-metadata — 7.6).

DI nega muhim? Uchta katta sabab: (1) Toza kod (class o'z ishiga e'tibor beradi, bog'liqlik yaratish bilan band emas); (2) Testlanadigan (test'da real DB o'rniga mock beramiz — DI buni oson qiladi — 8.11); (3) Moslashuvchan (implementatsiyani almashtirish oson — interface + DI — 9: SOLID DIP). Bu bob: DI nima va nega, IoC konteyner ichki ishlashi, provider turlari (useClass/useValue/useFactory/useExisting), injection token, custom provider, va scope — chuqur, promptdan ancha ko'p.

O'xshatish (DI): DI'siz — oshpaz o'zi dalaga borib, sabzavot ekib, yig'ib, keyin ovqat pishiradi (har bog'liqlikni o'zi yaratadi — band, chalkash). DI bilan — oshpazga tayyor masalliqlar yetkazib beriladi (constructor orqali), u faqat o'z ishini (ovqat pishirish) qiladi. Kim masalliq yetkazadi (IoC konteyner) — oshpazni qiziqtirmaydi. Test'da — soxta masalliq (mock) beramiz. Toza, moslashuvchan, sinaladigan.

Nega muhim?

  • NestJS yuragi — butun framework DI ustiga qurilgan.
  • Toza kod — class o'z ishiga e'tibor (bog'liqlik yaratmaydi).
  • Testlanadigan — mock oson 8.11-bob — sifatli kod.
  • Moslashuvchan — interface + DI (9: SOLID DIP) — almashtirish oson.

2. Nazariya — chuqur tushuntirish

2.1. Bog'liqlik (dependency) nima

Dependency (bog'liqlik) — bir class ishlashi uchun kerak bo'lgan boshqa class/obyekt:

ts
class UserService {
  // UserService ishlashi uchun Database KERAK  Database — bog'liqlik
  private db = new Database();        //  o'zi yaratdi (qattiq bog'langan)
}

Bog'liqlik — "menga ishlash uchun bu kerak". UserServicega Database kerak (bog'liqlik). Muammo: new Database()qattiq bog'lanish (tight coupling — 2.2). DI buni hal qiladi 2.3-bob.

2.2. Qattiq bog'lanish muammosi (DI'siz)

ts
//  DI'siz — qattiq bog'lanish (tight coupling)
class UserService {
  private db = new Database("postgres://...");   // o'zi yaratadi
}
class OrderService {
  private db = new Database("postgres://...");   // yana yaratadi (takror!)
}
text
  Muammolar (DI'siz):
   Takror (har joyda new Database)
   Test qiyin (real DB'ni mock qilib bo'lmaydi — har joyda yangi)
   O'zgartirish qiyin (DB sozlamasi o'zgarsa — har joyni)
   Qattiq bog'lanish (UserService aniq Database'ga bog'liq)

Qattiq bog'lanish — class o'z bog'liqligini o'zi yaratadi (new). Bu — takror, test qiyin, o'zgartirish qiyin. DI bu muammoni hal qiladi (yaratish — tashqarida).

2.3. Dependency Injection (yechim)

DI — bog'liqlikni tashqaridan (constructor orqali) olish:

ts
//  DI — bog'liqlik tashqaridan (constructor)
@Injectable()
class UserService {
  constructor(private db: Database) {}   // Database TASHQARIDAN keladi (DI)
  // UserService Database'ni YARATMAYDI — faqat oladi va ishlatadi
}
text
  DI bilan:
   Takror yo'q (bitta Database — hammaga)
   Test oson (mock Database berish)
   O'zgartirish bir joyda (DB sozlamasi — bir marta)
   Bo'sh bog'lanish (loose coupling)

DI mohiyati: class bog'liqlikni so'raydi (constructor parametri), kimdir (IoC konteyner — 2.4) uni beradi. Class yaratish bilan band emas — o'z ishiga e'tibor. Bu — toza, testlanadigan, moslashuvchan kod (9: SOLID).

2.4. IoC (Inversion of Control) konteyner

IoC konteyner — bog'liqliklarni avtomatik yaratib, ulaydigan NestJS tizimi:

text
  An'anaviy nazorat (siz boshqarasiz):
  const db = new Database();
  const service = new UserService(db);     // SIZ yaratasiz, SIZ ulaysiz
  const controller = new UserController(service);

  Inversion of Control (konteyner boshqaradi):
   NestJS bootstrap (8.1: 2.10) da BARCHA provider'larni yaratadi
   Bog'liqliklarni TUR bo'yicha ulaydi (TS + reflect-metadata — 7.6)
   Siz faqat constructor'da SO'RAYSIZ, konteyner BERADI

  "Inversion" — yaratish nazorati SIZdan KONTEYNERga o'tdi

IoC konteyner — NestJS'ning "miyasi": ilova ishga tushganda (bootstrap) barcha provider'larni yaratadi, bir-biriga ulaydi (dependency graph), va kerakli joyga beradi. Siz — faqat so'raysiz (constructor); konteyner — hal qiladi. "Nazoratning teskari aylanishi" (yaratish — siz emas, konteyner).

2.5. DI qanday ishlaydi (under the hood — promptda yo'q)

text
  1. @Injectable() — "bu class DI'da ishtirok etadi" (metama'lumot — 7.6)
  2. emitDecoratorMetadata (tsconfig — 7.6: 2.3) — constructor parametr TURLARINI saqlaydi
  3. reflect-metadata (7.6: 2.10) — "design:paramtypes"  [Database, ...]
  4. NestJS bootstrap'da: UserService'ni yaratish kerak 
     uning constructor turlarini o'qiydi ([Database]) 
     Database'ni yaratadi (yoki mavjudini oladi)  UserService'ga beradi
  5. Singleton — bir marta yaratadi, qayta ishlatadi (2.13)

DI sehir emas, mexanizm (under the hood): NestJS TS turlaridan (constructor parametr turlari — reflect-metadata orqali — 7.6) qaysi bog'liqlik kerakligini biladi. constructor(private db: Database) NestJS Database turini o'qiydi uni yaratib beradi. Shuning uchun emitDecoratorMetadata (7.6: 2.3) majburiy (turlarsiz DI ishlamaydi).

2.6. Provider va injection token

Har provider token bilan ro'yxatga olinadi (DI konteynerda kalit):

ts
@Module({
  providers: [UserService],          // qisqa: token = class nomi (UserService)
})

// To'liq shakl (token aniq):
@Module({
  providers: [
    { provide: UserService, useClass: UserService },   // provide — token; useClass — qiymat
  ],
})

Injection token — DI konteynerda provider'ni topish uchun kalit. Qisqa shaklda (providers: [UserService]) — token = class nomi. To'liq shaklda — provide (token) + qiymat (useClass/useValue/... — 2.7). Token class, string yoki Symbol bo'lishi mumkin 2.10-bob.

2.7. Custom provider turlari (4 ta — chuqur)

Standart providers: [Service] dan tashqari, 4 xil custom provider:

text
  useClass   — class instansiyasi (default; almashtirish mumkin)
  useValue   — tayyor qiymat (config, mock, konstanta)
  useFactory — funksiya yaratadi (dinamik, async, bog'liqlik bilan)
  useExisting — alias (mavjud provider'ga boshqa nom)

Custom provider'lar — DI'ning to'liq kuchi: nafaqat class, balki qiymat (useValue — config), funksiya natijasi (useFactory — dinamik), alias (useExisting). Bu — NestJS ekotizimining (8.1: 2.17) asosi (TypeOrmModule, ConfigModule shularni ishlatadi).

2.8. useClass (class provider)

ts
// useClass — token uchun class instansiyasi (almashtirish — 9: DIP)
@Module({
  providers: [
    {
      provide: PaymentService,         // token (interface/abstract)
      useClass: process.env.NODE_ENV === "production"
        ? RealPaymentService           // production — haqiqiy
        : MockPaymentService,          // dev — soxta (5.8)
    },
  ],
})
// PaymentService inject qilinganda — muhitga qarab Real yoki Mock

useClass — token uchun class beradi (default providers: [X] = useClass: X). Kuchi: implementatsiyani almashtirish (interface token, muhitga qarab class — 9: DIP). Test'da real o'rniga mock 8.11-bob. Bu — moslashuvchanlikning asosi.

2.9. useValue (qiymat provider)

ts
// useValue — tayyor qiymat (config, konstanta, mock)
const config = { apiKey: "...", timeout: 5000 };

@Module({
  providers: [
    { provide: "CONFIG", useValue: config },           // tayyor obyekt
    { provide: "API_KEY", useValue: process.env.KEY },  // konstanta (5.8)
  ],
})

// Inject (string token  @Inject — 2.10)
@Injectable()
class Service {
  constructor(@Inject("CONFIG") private config: any) {}
}

useValuetayyor qiymat (class emas): konfiguratsiya, konstanta, tashqi kutubxona instansiyasi, yoki mock (test'da — 8.11). String token bo'lsa @Inject kerak 2.10-bob. Bu — qiymatlarni DI konteynerga qo'shish.

2.10. Injection token: class, string, Symbol

ts
// 1. Class token (eng oddiy — @Inject kerak emas)
constructor(private service: UserService) {}

// 2. String token (@Inject kerak)
constructor(@Inject("CONFIG") private config: Config) {}

// 3. Symbol/konstanta token (typo'siz — tavsiya)
export const CONFIG = Symbol("CONFIG");              // yoki const CONFIG = "CONFIG"
constructor(@Inject(CONFIG) private config: Config) {}

String token o'rniga konstanta/Symbol (best practices): @Inject("CONFIG") — typo xavfi ("CONIFG" — topilmaydi). Konstanta (const CONFIG_TOKEN = "CONFIG") yoki Symbol — typo'siz, IDE yordami. Class token — eng oddiy (@Inject kerak emas — tur bo'yicha). Interface token bo'lolmaydi (runtime'da yo'q — 7.1: 2.4) string/Symbol/abstract class.

2.11. useFactory (dinamik provider)

ts
// useFactory — funksiya yaratadi (dinamik, async, bog'liqlik bilan)
@Module({
  providers: [
    {
      provide: "DATABASE",
      useFactory: async (config: ConfigService) => {   // bog'liqlik (inject)
        const db = await connectDB(config.get("DB_URL"));   // async!
        return db;
      },
      inject: [ConfigService],                          // factory'ga inject (2.11)
    },
  ],
})

useFactory — eng kuchli custom provider: funksiya provider'ni yaratadi. Dinamik (shartga qarab), async (DB ulanish — 8.3), bog'liqlik bilan (inject — factory'ga boshqa provider). NestJS ekotizimi (forRoot — 8.1: 2.13) ko'pincha useFactory ishlatadi.

2.12. useExisting (alias)

ts
// useExisting — mavjud provider'ga boshqa nom (alias — bir instansiya)
@Module({
  providers: [
    LoggerService,
    { provide: "AppLogger", useExisting: LoggerService },   // alias
  ],
})
// "AppLogger" va LoggerService — BIR XIL instansiya (useClass yangisini yaratardi)

useExisting — mavjud provider'ga ikkinchi nom (alias). useClassdan farqi: yangi instansiya yaratmaydi — mavjudini ko'rsatadi (singleton). Eski API moslik, yoki bir provider'ga turli token. Kamdan-kam, lekin foydali.

2.13. Provider scope (lifetime — chuqur)

Scope — provider qancha yashashi (8.1: 2.14 — bu yerda chuqur):

text
  DEFAULT (Singleton):
  - Bootstrap'da BIR MARTA yaratiladi
  - Butun ilovada BIR instansiya (hamma ishlatadi)
  - Eng tez, eng ko'p ishlatiladi

  REQUEST:
  - Har HTTP so'rovga YANGI instansiya
  - Shu so'rovdagi hamma service bir instansiyani ulashadi
  - So'rovga xos ma'lumot (request user, request logger — 5.12)
  - SEKINROQ (har so'rovda yaratish)

  TRANSIENT:
  - Har INJECT'ga yangi instansiya (ulashmaydi)
  - Kamdan-kam (har joyda alohida holat kerak bo'lganda)
ts
@Injectable({ scope: Scope.REQUEST })       // har so'rovga yangi
export class RequestScopedService {}

Scope tanlovi: Singleton (default) — 95% holat (tez, holatsiz service). REQUEST — so'rovga xos kontekst (joriy foydalanuvchi, correlation ID — 5.12); lekin sekinroq (har so'rovda yaratish + butun zanjir request-scoped bo'ladi). TRANSIENT — har inject alohida. Default'da qoling; REQUEST — faqat zarur bo'lganda.

2.14. Scope bubbling (muhim nuans — promptda yo'q)

Scope "yuqoriga ko'tariladi": agar provider REQUEST-scoped bo'lsa, uni ishlatadigan hamma ham REQUEST bo'ladi:

text
  Controller  Service A (REQUEST)  ...
   Controller ham REQUEST bo'ladi (scope bubbling)
   butun zanjir REQUEST (sekinroq)

   REQUEST/TRANSIENT'ni Singleton'ga inject qilib BO'LMAYDI
     (singleton bir marta yaratiladi — request'ni qayerdan oladi?)
      RuntimeException

Scope bubbling (best practices): REQUEST-scoped provider ishlatadigan zanjir — butunlay REQUEST bo'ladi (performance ta'siri). Va REQUEST'ni singleton'ga inject qilib bo'lmaydi (xato). Aralash kerak bo'lsa — useFactory yoki REQUEST token 8.2-bob. Bu — DI'ning nozik, lekin muhim tomoni.

2.15. Property vs constructor injection

ts
//  Constructor injection (TAVSIYA)
@Injectable()
class Service {
  constructor(private db: Database) {}   // hamma bog'liqlik yaratishda mavjud
}

// Property injection (kamdan-kam — faqat optional/circular)
@Injectable()
class Service {
  @Inject(Database) private db: Database;   // xususiyatga
}

Constructor injection afzal (best practices): hamma bog'liqlik obyekt yaratilganda mavjud (kutilmagan runtime xato kam); aniq (constructor — bog'liqliklar ro'yxati); test oson. Property injection — faqat maxsus holat (ixtiyoriy bog'liqlik, ba'zi circular — 2.16).

2.16. Circular dependency va forwardRef

Circular dependency — ikki provider/modul bir-birini ishlatadi (aylana):

ts
// A  B, B  A (aylana — NestJS hal qila olmaydi)
@Injectable()
class UserService {
  constructor(private orderService: OrderService) {}   // A  B
}
@Injectable()
class OrderService {
  constructor(private userService: UserService) {}     // B  A (aylana!)
}

// Yechim: forwardRef (kechiktirilgan hal qilish)
@Injectable()
class UserService {
  constructor(@Inject(forwardRef(() => OrderService)) private orderService: OrderService) {}
}

Circular dependency — A B'ga, B A'ga bog'liq (NestJS qaysidan boshlashni bilmaydi). forwardRef(() => X) — "bu bog'liqlikni keyinroq hal qil" (kechiktirilgan). Lekin — circular — ko'pincha dizayn xatosi (9): uchinchi service'ga ajratish yoki event ishlatish afzal. forwardRef — oxirgi chora.

2.17. DI va testlanadigan kod (8.11 ko'prik)

DI'ning eng katta foydasi — test 8.11-bob:

ts
// DI tufayli test'da real DB o'rniga MOCK (8.11)
const moduleRef = await Test.createTestingModule({
  providers: [
    UserService,
    { provide: Database, useValue: mockDatabase },   // mock! (useValue — 2.9)
  ],
}).compile();

const service = moduleRef.get(UserService);
// service real Database o'rniga mockDatabase ishlatadi (test izolyatsiyasi)

DI = testlanadigan kod: DI tufayli test'da real bog'liqlik (DB, email) o'rniga mock beramiz (useValue — 2.9). UserService o'zgarmaydi — faqat unga boshqa Database beriladi (DI). Bu — unit test'ning asosi 8.11-bob. DI'siz — bu juda qiyin (real DB kerak).

2.18. DI va SOLID (DIP — 9 ko'prik)

ts
// Interface (abstraksiya) — 9: Dependency Inversion Principle
interface IPaymentGateway {
  charge(amount: number): Promise<boolean>;
}

@Injectable()
class OrderService {
  constructor(
    @Inject("PAYMENT") private payment: IPaymentGateway,   // INTERFACE'ga bog'liq
  ) {}
}

@Module({
  providers: [
    { provide: "PAYMENT", useClass: StripeGateway },   // implementatsiya (almashtirsa bo'ladi)
  ],
})

DI + interface = DIP (9: SOLID): yuqori daraja (OrderService) interfacega bog'liq (aniq class'ga emas). Implementatsiya (Stripe/Payme) — DI orqali beriladi (almashtirsa bo'ladi). Bu — toza arxitektura (9). Interface runtime'da yo'q 7.1-bob string/abstract class token 2.10-bob.

2.19. @Optional() — ixtiyoriy bog'liqlik

Odatda bog'liqlik majburiy: provider topilmasa — NestJS xato beradi (6: 1-xato). Ba'zan bog'liqlik ixtiyoriy bo'lishi kerak (bo'lsa ishlat, bo'lmasa — undefined):

ts
import { Injectable, Optional, Inject } from "@nestjs/common";

@Injectable()
export class HttpClient {
  // @Optional() — provider topilmasa xato EMAS, faqat undefined
  constructor(
    @Optional() @Inject("HTTP_OPTIONS") private options?: HttpOptions,
  ) {
    this.options = options ?? { timeout: 5000 };   // default (bo'lmasa)
  }
}

@Optional() — bog'liqlikni ixtiyoriy qiladi: DI konteyner uni topa olmasa, xato o'rniga undefined beradi (siz default qo'yasiz). Ko'proq qayta ishlatiladigan kutubxona/modullarda foydali (foydalanuvchi config bermasligi mumkin). Odatiy service'da — majburiy bog'liqlik afzal (yetishmasa darrov xato — 6: 1-xato). @Optional() @Inject() bilan birga (yoki class token uchun yolg'iz) ishlatiladi.

2.20. ModuleRef — dasturiy (imperative) DI

Odatda bog'liqlik constructor orqali deklarativ olinadi. Ba'zan provider'ni kod ichida, dinamik (ish vaqtida) olish kerak — buning uchun ModuleRef:

ts
import { Injectable, OnModuleInit } from "@nestjs/common";
import { ModuleRef } from "@nestjs/core";

@Injectable()
export class TaskRunner implements OnModuleInit {
  private handler: HandlerService;

  constructor(private moduleRef: ModuleRef) {}   // ModuleRef inject (o'zi mavjud)

  onModuleInit() {
    // get — SINGLETON/mavjud instansiyani oladi (sinxron)
    this.handler = this.moduleRef.get(HandlerService, { strict: false });
  }

  async run() {
    // resolve — SCOPED (REQUEST/TRANSIENT) provider uchun YANGI instansiya (async)
    const scoped = await this.moduleRef.resolve(ScopedService);
    scoped.doWork();
  }
}

ModuleRef — dasturiy DI: konteyner bilan kod ichida ishlash imkoni. get(Token) — mavjud (singleton) provider'ni sinxron oladi ({ strict: false } — butun ilovadan izlaydi, faqat joriy modul emas). resolve(Token) — scoped (REQUEST/TRANSIENT — 2.13) provider'ning yangi instansiyasini Promise bilan qaytaradi. Qachon kerak: dinamik handler tanlash (strategy — token ish vaqtida ma'lum), plagin tizimi, yoki ba'zi circular holatlar (2.16 forwardRef muqobili). Odatda constructor injection afzal — ModuleRef faqat dinamik zarurat bo'lganda.

2.21. Dynamic module (register / forRoot / forFeature naqshi)

Odatiy modul statik (@Module({...}) — o'zgarmas). Dinamik modul — konfiguratsiya bilan sozlanadigan modul: chaqirilganda parametr qabul qiladi va provider'larni shu parametrga qarab yaratadi. Bu — NestJS ekotizimining (ConfigModule.forRoot(), TypeOrmModule.forRoot(), JwtModule.register() — 8.1: 2.17) asosidagi naqsh:

ts
import { DynamicModule, Module } from "@nestjs/common";

export const CONFIG_OPTIONS = Symbol("CONFIG_OPTIONS");

interface ConfigModuleOptions { folder: string; }

@Module({})
export class ConfigModule {
  // register / forRoot — SINXRON sozlash (parametr  provider)
  static forRoot(options: ConfigModuleOptions): DynamicModule {
    return {
      module: ConfigModule,
      providers: [
        { provide: CONFIG_OPTIONS, useValue: options },   // parametrni provider'ga
        ConfigService,
      ],
      exports: [ConfigService],
      global: true,   // ixtiyoriy: global modul (har joyda import'siz — 8.1)
    };
  }
}

// Ishlatish (root modulda):
@Module({
  imports: [ConfigModule.forRoot({ folder: "./config" })],   // parametr bilan
})
export class AppModule {}

Dinamik modul (naqsh): metod (forRoot/register/forFeature) DynamicModule obyekt qaytaradi (module + providers/imports/exports). Konvensiya: forRoot/forRootAsync — ilova bo'yicha bir marta global sozlash (DB, config); register/registerAsync — har import'da alohida sozlash (masalan, HttpModule.register({...})); forFeature — modulning bir qismini (feature) ro'yxatga olish (TypeOrmModule.forFeature([User]) — 8.3). Parametrni provider'ga aylantirib (useValue), modul ichidagi service uni inject qiladi (@Inject(CONFIG_OPTIONS)).

2.22. forRootAsync / registerAsync (async sozlash)

Sozlash qiymati ish vaqtida, boshqa provider'dan kelsa (masalan, ConfigServicedan DB URL) — async variant kerak. U useFactory + inject ishlatadi 2.11-bob:

ts
export class DatabaseModule {
  // forRootAsync — sozlash boshqa provider'ga bog'liq (useFactory + inject)
  static forRootAsync(): DynamicModule {
    return {
      module: DatabaseModule,
      imports: [ConfigModule],                     // ConfigService kerak
      providers: [
        {
          provide: "DB_CONNECTION",
          useFactory: async (config: ConfigService) => {   // async factory (2.11)
            return await createConnection(config.get("DB_URL"));
          },
          inject: [ConfigService],                 // factory bog'liqligi
        },
      ],
      exports: ["DB_CONNECTION"],
    };
  }
}

// Ishlatish:
@Module({ imports: [DatabaseModule.forRootAsync()] })
export class AppModule {}

forRootAsync / registerAsync: sozlash qiymati statik emas — u boshqa provider (ConfigService), tashqi manba yoki Promisedan keladi. Yechim: useFactory 2.11-bob + inject. Ekotizim modullari (TypeOrmModule.forRootAsync, JwtModule.registerAsync) shu naqshni useFactory (yoki useClass/useExisting bilan optionsFactory) sifatida taklif qiladi. Bu — DI'ning kutubxona darajasidagi eng kuchli ko'rinishi (dinamik modul + async provider birga).

2.23. Async provider (useFactory + Promise)

Provider'ning o'zi asinxron yaratilishi mumkin (DB ulanish, tashqi resurs). useFactory async/Promise qaytarsa — NestJS ulanishni kutadi, keyin ilovani ishga tushiradi:

ts
{
  provide: "ASYNC_CONNECTION",
  useFactory: async (): Promise<Connection> => {
    const conn = await createConnection();   // NestJS bu Promise'ni KUTADI
    return conn;                             // faqat ulangach — inject tayyor
  },
}
//  Ilova bootstrap'i shu async provider tayyor bo'lguncha KUTADI
//    (ya'ni DB ulanmaguncha ilova so'rov qabul qilmaydi — xavfsiz)

Async provider: useFactory Promise (yoki async) qaytarsa, NestJS hal bo'lishini kutadi va hal qilingan qiymatni inject qiladi (Promise'ni emas). Foydasi: ilova faqat bog'liqlik (DB, cache) tayyor bo'lgach so'rov qabul qiladi (yarim-tayyor holatda emas). Bu — 8.3 (DB ulanish) va cache (Redis — 5.21) uchun asosiy naqsh.

2.24. DI konteyner ichki ishlashi (chuqurroq — under the hood)

2.5'da qisqacha ko'rdik; endi qadamma-qadam:

text
  1. TARANG (scan): NestJS bootstrap'da barcha modullarni o'qiydi,
     har modul providers/imports/exports'ini yig'adi (metama'lumot — 7.6).

  2. TOKEN  PROVIDER xaritasi: har token uchun qanday yaratishni belgilaydi
     (useClass/useValue/useFactory/useExisting — 2.7). Bu — "provider registri".

  3. BOG'LIQLIK GRAFI: har provider constructor turlarini o'qiydi
     (design:paramtypes — reflect-metadata — 7.6)  kim kimga bog'liq.

  4. TOPOLOGIK TARTIB: grafni tartiblaydi (bog'liqligi yo'qdan boshlab).
     Circular bo'lsa — aniqlaydi (6: 3-xato) yoki forwardRef kutadi 2.16-bob.

  5. INSTANSIYALASH: tartib bo'yicha yaratadi. Har token uchun:
     - useValue  qiymatni oladi (yaratmaydi)
     - useClass  new Class(...bog'liqliklar)
     - useFactory  factory(...inject) (async bo'lsa — kutadi — 2.23)
     - Singleton  keshlaydi 2.13-bob; qayta so'ralsa — o'sha instansiya

  6. INJECT: yaratilgan instansiyalarni constructor'larga uzatadi.
     Ilova tayyor — so'rovlarni qabul qiladi.

DI konteyner (mohiyat): konteyner — bu token provider registri + bog'liqlik grafi + instansiya keshi (singleton uchun). Bootstrap'da grafni topologik tartiblab (bog'liqligi yo'qidan boshlab) instansiyalaydi. Shuning uchun circular muammo (graf aylanasi — qayerdan boshlash noaniq — 2.16), va shuning uchun turlar majburiy (graf turlardan quriladi — emitDecoratorMetadata — 2.5, 7.6). REQUEST-scoped provider'lar bootstrap'da emas, har so'rovda yaratiladi 2.13-bob — shuning uchun sekinroq. Bu manzarani tushunish — DI xatolarini (6) darrov hal qilishning kaliti.

2.25. Best practices (DI)

text
   Constructor injection (property emas — 2.15)
   Default singleton scope (REQUEST/TRANSIENT ehtiyot — 2.13, 2.14)
   Custom provider'lar (useValue config, useFactory dinamik — 2.7)
   Token: konstanta/Symbol (string typo — 2.10)
   Interface + useClass (DIP — almashtirish/test — 2.8, 2.18)
   Circular dependency — qayta dizayn (forwardRef oxirgi chora — 2.16)
   REQUEST'ni singleton'ga inject qilmang 2.14-bob
   DI  mock (testlanadigan — 2.17, 8.11)
   @Optional() — faqat haqiqiy ixtiyoriy bog'liqlik 2.19-bob
   ModuleRef — faqat dinamik zarurat (deklarativ DI afzal — 2.20)
   Dynamic module: forRoot (global) / register (har import) / forFeature 2.21-bob
   Async sozlash  forRootAsync (useFactory + inject — 2.22)
   Async provider — DB/cache tayyor bo'lgach ilova (2.23)

3. Sintaksis — tez ma'lumotnoma

ts
// Oddiy DI (2.3)
@Injectable() class Service { constructor(private dep: OtherService) {} }

// Custom provider'lar (2.7-2.12)
{ provide: TOKEN, useClass: X }       // class
{ provide: TOKEN, useValue: qiymat }  // qiymat
{ provide: TOKEN, useFactory: (dep) => {...}, inject: [Dep] }   // factory
{ provide: TOKEN, useExisting: X }    // alias

// Token (2.10)
@Inject("STRING_TOKEN") yoki @Inject(SYMBOL_TOKEN)

// Scope 2.13-bob: @Injectable({ scope: Scope.REQUEST })
// Circular 2.16-bob: @Inject(forwardRef(() => X))

// Ixtiyoriy (2.19)
constructor(@Optional() @Inject(TOKEN) private x?: T) {}

// ModuleRef — dasturiy DI (2.20)
constructor(private moduleRef: ModuleRef) {}
this.moduleRef.get(Service, { strict: false });   // singleton (sinxron)
await this.moduleRef.resolve(ScopedService);       // scoped (async)

// Dynamic module (2.21, 2.22)
static forRoot(opts): DynamicModule { return { module: X, providers: [...], exports: [...] }; }
static forRootAsync(): DynamicModule { /* useFactory + inject */ }

4. Batafsil kod namunalari

Misol 1 — DI'siz vs DI bilan (2.2, 2.3)

ts
//  DI'siz — qattiq bog'lanish (2.2)
class UserService {
  private db = new Database("postgres://...");   // o'zi yaratadi
  private email = new EmailService();            // yana yaratadi
  // test: real DB/email kerak (qiyin); o'zgartirish: har joyni
}

//  DI bilan — bo'sh bog'lanish (2.3)
@Injectable()
class UserService {
  constructor(
    private db: Database,                        // tashqaridan (DI)
    private email: EmailService,                 // tashqaridan
  ) {}
  // test: mock berish oson; bir instansiya hammaga; toza
}

Misol 2 — Standart DI (8.1 takrori — 2.3)

ts
@Injectable()
export class EmailService {                       // (5.19)
  yubor(to: string, matn: string) { /* ... */ }
}

@Injectable()
export class UsersService {
  constructor(private emailService: EmailService) {}   // DI (NestJS o'zi beradi)

  async yarat(dto: CreateUserDto) {
    const user = { id: 1, ...dto };
    await this.emailService.yubor(user.email, "Xush kelibsiz!");   // boshqa service
    return user;
  }
}

@Module({
  providers: [UsersService, EmailService],        // ikkalasi ro'yxatda (2.6)
})
export class UsersModule {}

Misol 3 — useValue (config, konstanta — 2.9)

ts
// Konfiguratsiya provider (useValue — 2.9)
export const APP_CONFIG = Symbol("APP_CONFIG");   // token (Symbol — 2.10)

interface AppConfig { apiKey: string; timeout: number; }

@Module({
  providers: [
    {
      provide: APP_CONFIG,
      useValue: { apiKey: process.env.API_KEY, timeout: 5000 } as AppConfig,   // (5.8)
    },
  ],
  exports: [APP_CONFIG],
})
export class ConfigModule {}

// Inject
@Injectable()
export class ApiService {
  constructor(@Inject(APP_CONFIG) private config: AppConfig) {}   // (2.10)
  sorov() { console.log(this.config.apiKey); }
}

Misol 4 — useFactory (dinamik, async — 2.11)

ts
// DB ulanish factory (async, bog'liqlik bilan — 2.11)
import { ConfigService } from "@nestjs/config";   // (8.14)

export const DATABASE = Symbol("DATABASE");

@Module({
  providers: [
    {
      provide: DATABASE,
      useFactory: async (config: ConfigService) => {   // factory + inject
        const db = await createConnection({              // async (8.3)
          url: config.get("DATABASE_URL"),
        });
        return db;
      },
      inject: [ConfigService],                          // factory bog'liqligi
    },
  ],
  exports: [DATABASE],
})
export class DatabaseModule {}

Misol 5 — useClass (almashtirish — DIP — 2.8, 2.18)

ts
// Interface (abstraksiya — 9: DIP)
export interface IPaymentGateway {
  charge(amount: number, card: string): Promise<{ success: boolean }>;
}
export const PAYMENT_GATEWAY = Symbol("PAYMENT_GATEWAY");

// Ikki implementatsiya
@Injectable()
export class StripeGateway implements IPaymentGateway {
  async charge(amount: number, card: string) { return { success: true }; }
}
@Injectable()
export class MockGateway implements IPaymentGateway {   // test/dev (8.11)
  async charge() { return { success: true }; }
}

// Muhitga qarab tanlash (useClass — 2.8)
@Module({
  providers: [
    {
      provide: PAYMENT_GATEWAY,
      useClass: process.env.NODE_ENV === "production" ? StripeGateway : MockGateway,
    },
  ],
})
export class PaymentModule {}

// OrderService interface'ga bog'liq (almashtirsa bo'ladi — DIP)
@Injectable()
export class OrderService {
  constructor(@Inject(PAYMENT_GATEWAY) private payment: IPaymentGateway) {}
}

Misol 6 — Scope: REQUEST (so'rovga xos — 2.13)

ts
import { Injectable, Scope, Inject } from "@nestjs/common";
import { REQUEST } from "@nestjs/core";
import { Request } from "express";

// Har so'rovga yangi (so'rovga xos kontekst — 2.13)
@Injectable({ scope: Scope.REQUEST })
export class RequestLogger {
  constructor(@Inject(REQUEST) private req: Request) {}   // joriy so'rov

  log(xabar: string) {
    console.log(`[${this.req.method} ${this.req.url}] ${xabar}`);   // (5.12)
  }
}
//  Bu service'ni ishlatadigan zanjir REQUEST bo'ladi (bubbling — 2.14)

Misol 7 — forwardRef (circular — 2.16)

ts
import { Injectable, Inject, forwardRef } from "@nestjs/common";

@Injectable()
export class UserService {
  constructor(
    @Inject(forwardRef(() => OrderService))    // kechiktirilgan (circular — 2.16)
    private orderService: OrderService,
  ) {}
}

@Injectable()
export class OrderService {
  constructor(
    @Inject(forwardRef(() => UserService))
    private userService: UserService,
  ) {}
}
//  Yaxshiroq: circular'ni QAYTA DIZAYN qiling (uchinchi service yoki event — 2.16, 9)

Misol 8 — DI bilan test (mock — 2.17, 8.11)

ts
import { Test } from "@nestjs/testing";

describe("UsersService", () => {
  let service: UsersService;
  const mockEmail = { yubor: jest.fn() };          // mock (8.11)

  beforeEach(async () => {
    const moduleRef = await Test.createTestingModule({
      providers: [
        UsersService,
        { provide: EmailService, useValue: mockEmail },   // real o'rniga mock (2.9, 2.17)
      ],
    }).compile();
    service = moduleRef.get(UsersService);
  });

  it("yangi user yaratganda email yuboradi", async () => {
    await service.yarat({ ism: "Ali", email: "ali@a.uz" });
    expect(mockEmail.yubor).toHaveBeenCalled();    // mock tekshiruvi
  });
});
// DI tufayli — real email o'rniga mock (test izolyatsiyasi — 8.11)

Misol 9 — Repository pattern + DI (9: Clean Architecture)

ts
// Interface (abstraksiya — 9: DIP)
export interface IUserRepository {
  topId(id: number): Promise<User | null>;
  saqla(user: User): Promise<User>;
}
export const USER_REPOSITORY = Symbol("USER_REPOSITORY");

// Implementatsiya (TypeORM — 8.3)
@Injectable()
export class TypeOrmUserRepository implements IUserRepository {
  async topId(id: number) { /* TypeORM 8.3-bob */ return null; }
  async saqla(user: User) { return user; }
}

// Service interface'ga bog'liq (DB texnologiyasini bilmaydi — 9)
@Injectable()
export class UsersService {
  constructor(@Inject(USER_REPOSITORY) private repo: IUserRepository) {}
  topId(id: number) { return this.repo.topId(id); }
}

@Module({
  providers: [
    UsersService,
    { provide: USER_REPOSITORY, useClass: TypeOrmUserRepository },   // almashtirsa bo'ladi
  ],
})
export class UsersModule {}
// Mongoose'ga o'tsangiz — faqat useClass'ni almashtirasiz (service o'zgarmaydi — DIP)

Misol 10 — Bir nechta provider birga (real modul)

ts
@Module({
  imports: [ConfigModule],                          // boshqa modul (2.6)
  controllers: [UsersController],
  providers: [
    UsersService,                                   // useClass (default)
    EmailService,
    { provide: USER_REPOSITORY, useClass: TypeOrmUserRepository },   // interface
    {
      provide: "CACHE",                             // string token
      useFactory: (config: ConfigService) => new Redis(config.get("REDIS_URL")),   // (5.21)
      inject: [ConfigService],
    },
  ],
  exports: [UsersService],                          // ulashish (2.6)
})
export class UsersModule {}

Misol 11 — @Optional() + useExisting (ixtiyoriy + alias — 2.19, 2.12)

ts
import { Injectable, Optional, Inject, Module } from "@nestjs/common";

// Ixtiyoriy config bilan qayta ishlatiladigan service (2.19)
@Injectable()
export class CacheClient {
  private ttl: number;
  constructor(
    @Optional() @Inject("CACHE_OPTIONS") options?: { ttl?: number },   // ixtiyoriy
  ) {
    this.ttl = options?.ttl ?? 60;   // provider yo'q bo'lsa — default (undefined)
  }
}

@Injectable()
export class LoggerService {
  log(m: string) { console.log(m); }
}

@Module({
  providers: [
    CacheClient,                                       // CACHE_OPTIONS bermadik — @Optional ishlaydi
    LoggerService,
    { provide: "AppLogger", useExisting: LoggerService },   // alias — BIR instansiya (2.12)
  ],
})
export class InfraModule {}
// "AppLogger" va LoggerService — bir xil obyekt (useExisting — 2.12)

Misol 12 — ModuleRef: dinamik strategiya tanlash (2.20)

ts
import { Injectable, OnModuleInit } from "@nestjs/common";
import { ModuleRef } from "@nestjs/core";

// Har provayder (Stripe/Payme) — alohida strategiya service
@Injectable() export class StripeStrategy { pay() { /* ... */ } }
@Injectable() export class PaymeStrategy { pay() { /* ... */ } }

@Injectable()
export class PaymentRouter implements OnModuleInit {
  private strategies = new Map<string, StripeStrategy | PaymeStrategy>();

  constructor(private moduleRef: ModuleRef) {}   // ModuleRef (2.20)

  onModuleInit() {
    // Token ish vaqtida ma'lum — get bilan dinamik olamiz
    this.strategies.set("stripe", this.moduleRef.get(StripeStrategy));
    this.strategies.set("payme", this.moduleRef.get(PaymeStrategy));
  }

  pay(provider: string) {
    this.strategies.get(provider)?.pay();   // dinamik tanlash
  }
}

@Module({ providers: [PaymentRouter, StripeStrategy, PaymeStrategy] })
export class PaymentModule {}

Misol 13 — Dynamic module: forRoot + forRootAsync (2.21, 2.22)

ts
import { DynamicModule, Module, Inject, Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";   // (8.14)

export const STORAGE_OPTIONS = Symbol("STORAGE_OPTIONS");

interface StorageOptions { bucket: string; }

@Injectable()
export class StorageService {
  constructor(@Inject(STORAGE_OPTIONS) private opts: StorageOptions) {}
  bucket() { return this.opts.bucket; }
}

@Module({})
export class StorageModule {
  // Sinxron sozlash (2.21)
  static forRoot(options: StorageOptions): DynamicModule {
    return {
      module: StorageModule,
      providers: [
        { provide: STORAGE_OPTIONS, useValue: options },   // parametr  provider
        StorageService,
      ],
      exports: [StorageService],
      global: true,
    };
  }

  // Async sozlash — qiymat ConfigService'dan (2.22)
  static forRootAsync(): DynamicModule {
    return {
      module: StorageModule,
      imports: [ConfigModule],
      providers: [
        {
          provide: STORAGE_OPTIONS,
          useFactory: (config: ConfigService) => ({    // dinamik (2.11)
            bucket: config.get("STORAGE_BUCKET"),
          }),
          inject: [ConfigService],
        },
        StorageService,
      ],
      exports: [StorageService],
    };
  }
}

// Ishlatish:
@Module({
  imports: [
    StorageModule.forRoot({ bucket: "static" }),        // sinxron
    // yoki: StorageModule.forRootAsync(),               // async (ENV'dan)
  ],
})
export class AppModule {}

5. To'g'ri va noto'g'ri holatlar

1) new bilan yaratish (DI o'rniga)

ts
//  qattiq bog'lanish (2.2)
class Service { private db = new Database(); }

//  DI (constructor)
@Injectable() class Service { constructor(private db: Database) {} }

2) Property injection (constructor o'rniga)

ts
//  property (kutilmagan xato — 2.15)
@Inject(Database) private db: Database;

//  constructor
constructor(private db: Database) {}

3) String token (typo xavfi)

ts
//  string (typo — 2.10)
@Inject("DATABSE")   // typo!

//  konstanta/Symbol
@Inject(DATABASE_TOKEN)

4) REQUEST scope'ni keraksiz ishlatish

text
 hamma service REQUEST (sekin — bubbling — 2.14)
 default singleton (REQUEST faqat so'rovga xos kontekst — 2.13)

5) Circular dependency (dizayn xatosi)

text
 AB circular  forwardRef (murakkab — 2.16)
 qayta dizayn (uchinchi service, event — 9)

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — Nest can't resolve dependencies of X (?)

Sababi: bog'liqlik provider'da yo'q, yoki modul import qilinmagan 2.6-bob. Yechimi: providers'ga qo'sh; boshqa moduldan bo'lsa — exports + imports; ? — qaysi parametr yetishmasligini ko'rsatadi.

Xato 2 — Cannot resolve ... reflect-metadata

Sababi: emitDecoratorMetadata yoki @Injectable yo'q (2.5, 7.6). Yechimi: tsconfig; @Injectable.

Xato 3 — Circular dependency detected

Sababi: AB aylana 2.16-bob. Yechimi: forwardRef; yoki qayta dizayn (afzal — 9).

Xato 4 — RuntimeException: scope mismatch

Sababi: REQUEST'ni singleton'ga inject 2.14-bob. Yechimi: scope'larni moslash; useFactory; REQUEST zanjirini cheklash.

Xato 5 — String token topilmadi

Sababi: token typo, yoki provider yo'q 2.10-bob. Yechimi: konstanta/Symbol token; provider ro'yxatda.

Xato 6 — useFactory bog'liqlik undefined

Sababi: inject array'da bog'liqlik yo'q 2.11-bob. Yechimi: inject: [Dep] qo'shing.

Xato 7 — moduleRef.get() scoped provider'da xato

Sababi: get() faqat singleton/mavjud instansiya uchun; REQUEST/TRANSIENT'da ishlamaydi 2.20-bob. Yechimi: scoped uchun await moduleRef.resolve(Token) ishlating.

Xato 8 — moduleRef.get() boshqa moduldan topmadi

Sababi: default get() faqat joriy modul kontekstida izlaydi 2.20-bob. Yechimi: moduleRef.get(Token, { strict: false }) — butun ilovadan izlaydi.

Xato 9 — Dynamic module provider export qilinmagan

Sababi: forRoot exportsida provider yo'q — import qilgan modul uni ko'rmaydi 2.21-bob. Yechimi: DynamicModule.exportsga qo'shing.

Xato 10 — forRootAsync'da inject yo'q factory bog'liqligi undefined

Sababi: async sozlashda useFactory bog'liqligi inject array'da yo'q, yoki kerakli modul importsda emas 2.22-bob. Yechimi: imports: [ConfigModule] + inject: [ConfigService].


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • NestJS arxitektura 8.1-bob: DI — uchlikning bog'lovchisi.
  • Decorators 7.6-bob: @Injectable, @Inject, reflect-metadata.
  • TypeScript (7): turlar — DI asosi (paramtypes).
  • DB 8.3-bob: repository DI; useFactory ulanish.
  • Config 8.14-bob: ConfigService DI; useValue; ConfigModule.forRoot (dinamik modul — 2.21).
  • Dinamik modul (8.1: 2.17): forRoot/register/forFeature — DI'ning kutubxona darajasi (2.21, 2.22).
  • Testing 8.11-bob: DI mock; moduleRef.get/resolve test'da 2.20-bob.
  • SOLID (9): DIP — interface + DI.
  • Clean architecture (9): repository pattern + DI.
  • Barcha NestJS (8): DI hamma joyda.

8. Eng yaxshi amaliyotlar (best practices)

  • Constructor injection (property emas — 2.15).
  • Default singleton (REQUEST/TRANSIENT ehtiyot — bubbling — 2.13, 2.14).
  • Custom provider'lar (useValue config, useFactory dinamik/async — 2.7).
  • Token: konstanta/Symbol (string typo'siz — 2.10).
  • Interface + useClass (DIP — almashtirish/test — 2.8, 2.18).
  • Circular — qayta dizayn (forwardRef oxirgi chora — 2.16).
  • REQUEST'ni singleton'ga inject qilmang 2.14-bob.
  • DI mock (testlanadigan — 2.17, 8.11).
  • Repository pattern + DI (DB abstraksiyasi — Misol 9, 9).
  • @Optional() faqat haqiqiy ixtiyoriy bog'liqlikda 2.19-bob.
  • ModuleRef faqat dinamik zaruratda (deklarativ constructor injection afzal — 2.20).
  • Dinamik modul naqshi: forRoot (global bir marta) / register (har import) / forFeature (2.21, 2.22).
  • Async sozlash forRootAsync — useFactory + inject 2.22-bob.
  • DI'ni tushun (sehir emas — reflect-metadata + bog'liqlik grafi mexanizmi — 2.5, 2.24).

9. Amaliy loyiha: "DI bilan Moslashuvchan Arxitektura"

Dependency Injection'ni chuqur mustahkamlash.

Maqsad

DI'ning to'liq kuchini ishlatib, moslashuvchan, testlanadigan arxitektura qurish: custom provider'lar, interface + DI (DIP), va mock bilan test.

Talablar (requirements)

  1. Standart DI: service'lar bir-biriga inject (Misol 2, 2.3).
  2. useValue: config provider (Symbol token — Misol 3, 2.9).
  3. useFactory: dinamik/async (DB yoki Redis ulanish — Misol 4, 10, 2.11).
  4. useClass + interface: payment gateway (muhitga qarab — DIP — Misol 5, 2.8, 2.18).
  5. Repository pattern: interface + DI (DB abstraksiyasi — Misol 9, 9).
  6. Token: Symbol/konstanta (string emas — 2.10).
  7. Scope: REQUEST service (so'rovga xos — Misol 6, 2.13).
  8. Test: mock bilan (useValue — Misol 8, 2.17).
  9. (Bonus) Circular: forwardRef yoki qayta dizayn 2.16-bob.
  10. Almashtirish: implementatsiyani o'zgartiring (service o'zgarmasligini ko'rsating — DIP).
  11. (Bonus) Dinamik modul: forRoot bilan sozlanadigan modul (Misol 13, 2.21).
  12. (Bonus) forRootAsync: ENV'dan async sozlash (useFactory + inject — 2.22).
  13. (Bonus) ModuleRef: dinamik strategiya tanlash (Misol 12, 2.20).
  14. (Bonus) @Optional(): ixtiyoriy bog'liqlik + default (Misol 11, 2.19).

Maslahatlar (hint)

  • Constructor injection (2.15, 2-xato).
  • Token: Symbol (string typo — 2.10, 3-xato).
  • useFactory: inject array (2.11, 6-xato).
  • Interface token: Symbol/abstract (runtime yo'q — 2.10, 2.18).
  • Test: useValue mock (2.17, Misol 8).
  • REQUEST ehtiyot (bubbling — 2.14).

"Tayyor" mezonlari (acceptance criteria)

  • Standart DI (service inject).
  • useValue (config, Symbol token).
  • useFactory (async/dinamik).
  • useClass + interface (DIP, almashtirish).
  • Repository pattern (interface + DI).
  • Token Symbol/konstanta.
  • REQUEST scope service.
  • Mock bilan test.
  • (Bonus) Circular yechimi.
  • Implementatsiya almashtirish (service o'zgarmaydi).
  • (Bonus) Dinamik modul (forRoot).
  • (Bonus) forRootAsync (async sozlash).
  • (Bonus) ModuleRef (dinamik olish).
  • (Bonus) @Optional() (ixtiyoriy bog'liqlik).

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda NestJS'ning yuragini — Dependency Injection ni — chuqur o'rgandik:

  • Bog'liqlik 2.1-bob; qattiq bog'lanish muammosi (2.2) DI yechimi (tashqaridan — 2.3).
  • IoC konteyner (avtomatik yaratish/ulash — 2.4); under the hood (reflect-metadata, paramtypes — 2.5); token (2.6, 2.10).
  • Custom provider'lar: useClass (almashtirish — 2.8), useValue (qiymat — 2.9), useFactory (dinamik/async — 2.11), useExisting (alias — 2.12).
  • Scope (singleton/request/transient — 2.13); bubbling 2.14-bob; constructor injection 2.15-bob; circular/forwardRef 2.16-bob; DI = testlanadigan + DIP (2.17, 2.18).
  • @Optional() (ixtiyoriy bog'liqlik — 2.19); ModuleRef (dasturiy DI — get/resolve — 2.20); dinamik modul (forRoot/register/forFeature — 2.21), forRootAsync 2.22-bob, async provider 2.23-bob; DI konteyner ichki ishlashi (registri + graf + kesh — 2.24).

Keyingi bob — 8.3-bob: DB ulanish — TypeORM / Prisma / Mongoose bilan. Arxitektura va DI'ni bildik; endi NestJS'ni ma'lumotlar bazasiga ulaymiz. 6-QISMda ORM'larni o'rgandik (TypeORM, Prisma, Mongoose); endi ularni NestJS'da — DI bilan integratsiyalashgan holda — ishlatamiz: @nestjs/typeorm, repository inject, modul sozlash. DB — har ilovaning yuragi.


Foydalanilgan rasmiy/ishonchli manbalar

  • docs.nestjs.com/fundamentals — Custom providers (useClass/useValue/useFactory/useExisting), Injection scopes, Module reference (ModuleRef — get/resolve)
  • docs.nestjs.com/fundamentals — Dynamic modules (forRoot/forRootAsync/register/forFeature), Asynchronous providers
  • docs.nestjs.com — Providers, Dependency Injection; forwardRef (circular); Optional dependencies (@Optional)

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
8.2-bob: Dependency Injection (chuqur) — Wisar