nestjs-custom-injector의 주 버전: 공급자가 설정되지 않은 경우 예외, 기본값 등에서 약속 사용...

설치




npm i --save nestjs-custom-injector


연결



https://github.com/EndyKaufman/nestjs-custom-injector - 라이브러리의 소스 코드
https://nestjs-custom-injector.site15.ru/api - nestjs-custom-injector를 사용한 데모 애플리케이션.
https://github.com/EndyKaufman/nestjs-custom-injector-example - nest cli로 생성된 예.

주요 변경 사항


  • getLastComponentByName 및 getLastComponentByClass를 다음으로 변경합니다.
    getProvider
  • getComponentsByName 및 getComponentsByClass를 다음으로 변경합니다.
    getProviders
  • CustomInject 데코레이터에서 정적 옵션 제거
  • defaultPropertyValue의 이름을 defaultProviderValue로 바꿉니다
  • .
  • 이제 응용 프로그램 라이브러리 검색을 시작한 후 모든 공급자 토큰이 필요하므로 항상 루트 응용 프로그램 모듈에서 CustomInjectorModule.forRoot()를 가져와야 합니다. 검사에서 공급자를 제외하려면 옵션을 추가하십시오@CustomInject(PROVIDER_TOKEN,{ lazy:true }).

  • 다중 공급자로 모든 기능을 테스트합니다.



    다중 공급자와 협력




    interface CProvider {
      type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class C1 implements CProvider {
      type = 'c1';
    }
    @Injectable()
    class C2 implements CProvider {
      type = 'c2';
    }
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER, { multi: true })
      providers!: CProvider[];
    }
    const module = await Test.createTestingModule({
      imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C1 }],
        }),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C2 }],
        }),
      ],
      providers: [P],
      exports: [P],
    }).compile();
    
    const app = module.createNestApplication();
    await app.init();
    const p = app.get<P>(P);
    expect(p.providers.map((o) => o.type)).toEqual(['c1', 'c2']);
    await app.close();
    


    다중 일반 및 비동기 공급자와 협력




    interface CProvider {
      type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class C1 implements CProvider {
      type = 'c1';
    }
    @Injectable()
    class C2 implements CProvider {
      type = 'c2';
    }
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER, { multi: true })
      providers!: CProvider[];
    }
    const module = await Test.createTestingModule({
      imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C1 }],
        }),
        CustomInjectorModule.forFeature({
          providers: [
            {
              provide: C_PROVIDER,
              useFactory: () =>
                new Promise((resolve) => setTimeout(() => resolve(new C2()), 1000)),
            },
          ],
        }),
      ],
      providers: [P],
      exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const p = app.get<P>(P);
    expect(p.providers.map((o) => o.type)).toEqual(['c1', 'c2']);
    await app.close();
    


    공급자 배열이 설정되지 않은 경우 오류




    interface CProvider {
      type: string;
    }
    const C_PROVIDER1 = 'C_PROVIDER1';
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER1, { multi: true })
      providers!: CProvider;
    }
    const module = await Test.createTestingModule({
      imports: [CustomInjectorModule.forRoot()],
      providers: [P],
      exports: [P],
    }).compile();
    const app = module.createNestApplication();
    try {
      await app.init();
      expect(true).toEqual(false);
    } catch (err) {
      expect(err instanceof CustomInjectorError && err.message).toEqual(
        `Providers "C_PROVIDER1" not found!`
      );
      expect(
        err instanceof CustomInjectorError &&
          err.injectedProvidersStorageItem?.token
      ).toEqual(C_PROVIDER1);
    }
    await app.close();
    


    공급자 배열이 설정되지 않은 경우 사용자 지정 오류




    interface CProvider {
        type: string;
    }
    class CustomError extends CustomInjectorError<CProvider> {
        constructor(public override message: string) {
        super(message);
        }
    }
    const C_PROVIDER1 = 'C_PROVIDER1';
    @Injectable()
    class P {
        @CustomInject<CProvider>(C_PROVIDER1, {
        multi: true,
        errorFactory: (message: string) => new CustomError(message),
        })
        providers!: CProvider;
    }
    const module = await Test.createTestingModule({
        imports: [CustomInjectorModule.forRoot()],
        providers: [P],
        exports: [P],
    }).compile();
    const app = module.createNestApplication();
    try {
        await app.init();
        expect(true).toEqual(false);
    } catch (err) {
        expect(err instanceof CustomError && err.message).toEqual(
        `Providers "C_PROVIDER1" not found!`
        );
        expect(
        err instanceof CustomError && err.injectedProvidersStorageItem?.token
        ).toEqual(undefined);
    }
    await app.close();
    });
    


    팩토리로 다중 제공자 생성




    interface CProvider {
      type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class C1 {
      name = 'c1';
    }
    @Injectable()
    class C2 {
      name = 'c2';
    }
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER, {
        multi: true,
        providerFactory: (data) => ({ type: data.name }),
      })
      providers!: CProvider[];
    }
    const module = await Test.createTestingModule({
      imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C1 }],
        }),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C2 }],
        }),
      ],
      providers: [P],
      exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const p = app.get<P>(P);
    expect(p.providers.map((o) => o.type)).toEqual(['c1', 'c2']);
    await app.close();
    


    비동기 팩토리로 다중 제공자 생성




    interface CProvider {
      type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class C1 {
      name = 'c1';
    }
    @Injectable()
    class C2 {
      name = 'c2';
    }
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER, {
        multi: true,
        providerFactory: (data) =>
          new Promise((resolve) =>
            setTimeout(() => resolve({ type: data.name }), 1000)
          ),
      })
      providers!: CProvider[];
    }
    const module = await Test.createTestingModule({
      imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C1 }],
        }),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C2 }],
        }),
      ],
      providers: [P],
      exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const p = app.get<P>(P);
    expect(p.providers.map((o) => o.type)).toEqual(['c1', 'c2']);
    await app.close();
    


    응용 프로그램 부트스트랩에서 설정하지 않고 데이터 가져오기에 지연 옵션을 사용하여 다중 공급자를 로드합니다.




    interface CProvider {
      type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class C1 implements CProvider {
      type = 'c1';
    }
    @Injectable()
    class C2 implements CProvider {
      type = 'c2';
    }
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER, { multi: true, lazy: true })
      providers!: CProvider[];
    }
    const module = await Test.createTestingModule({
      imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C1 }],
        }),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C2 }],
        }),
      ],
      providers: [P],
      exports: [P],
    }).compile();
    const app = module.createNestApplication();
    // we don't need start application, because providers marked with lazy options will be ignored when the application bootstrap
    // await app.init();
    const p = app.get<P>(P);
    expect(p.providers.map((o) => o.type)).toEqual(['c1', 'c2']);
    await app.close();
    


    런타임 시 다중 공급자 업데이트




    interface CProvider {
        type: string;
    }
    const C_PROVIDER_NEW = Symbol('C_PROVIDER_NEW');
    @Injectable()
    class C1 implements CProvider {
        type = 'c1';
    }
    @Injectable()
    class C2 implements CProvider {
        type = 'c2';
    }
    @Injectable()
    class P {
        @CustomInject<CProvider>(C_PROVIDER_NEW, { multi: true })
        providers!: CProvider[];
    }
    const module = await Test.createTestingModule({
        imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
            providers: [{ provide: C_PROVIDER_NEW, useValue: new C1() }],
        }),
        CustomInjectorModule.forFeature({
            providers: [{ provide: C_PROVIDER_NEW, useClass: C2 }],
        }),
        ],
        providers: [P],
        exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const p = app.get<P>(P);
    expect(p.providers.map((o) => o.type)).toEqual(['c1', 'c2']);
    p.providers.forEach((o) => {
        o.type = `updated ${o.type}`;
    });
    const p2 = app.get<P>(P);
    expect(p2.providers.map((o) => o.type)).toEqual([
        'updated c1',
        'updated c2',
    ]);
    await app.close();
    });
    


    런타임 시 공장에서 만든 다중 공급자 업데이트




    interface CProvider {
        type: string;
    }
    const C_PROVIDER_NEW = Symbol('C_PROVIDER_NEW');
    @Injectable()
    class C1 implements CProvider {
        type = 'c1';
    }
    @Injectable()
    class C2 implements CProvider {
        type = 'c2';
    }
    @Injectable()
    class P {
        @CustomInject<CProvider>(C_PROVIDER_NEW, {
        multi: true,
        providerFactory: (data) => ({ ...data, type: `factory ${data.type}` }),
        })
        providers!: CProvider[];
    }
    const module = await Test.createTestingModule({
        imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
            providers: [{ provide: C_PROVIDER_NEW, useValue: new C1() }],
        }),
        CustomInjectorModule.forFeature({
            providers: [{ provide: C_PROVIDER_NEW, useClass: C2 }],
        }),
        ],
        providers: [P],
        exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const providers = app.get<P>(P).providers;
    expect(providers.map((o) => o.type)).toEqual(['factory c1', 'factory c2']);
    providers.forEach((o) => {
        o.type = `updated ${o.type}`;
    });
    const currentProviders = [...app.get<P>(P).providers];
    expect(currentProviders.map((o) => o.type)).toEqual([
        'updated factory c1',
        'updated factory c2',
    ]);
    await app.close();
    });
    


    토큰 공급자를 찾을 수 없는 경우 기본 공급자 사용




    interface CProvider {
        type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class P {
        @CustomInject<CProvider>(C_PROVIDER, {
        multi: true,
        defaultProvidersValue: [],
        })
        providers!: CProvider[];
    }
    const module = await Test.createTestingModule({
        imports: [CustomInjectorModule.forRoot()],
        providers: [P],
        exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const providers = app.get<P>(P).providers;
    expect(providers).toEqual([]);
    await app.close();
    });
    


    다중 공급자 및 하위 속성으로 모든 기능을 테스트합니다.



    다중 공급자와 협력




    interface CProvider {
        type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class C1 implements CProvider {
        type = 'c1';
    }
    @Injectable()
    class C2 implements CProvider {
        type = 'c2';
    }
    @Injectable()
    class P {
        @CustomInject<CProvider>(C_PROVIDER, {
        multi: true,
        propertyName: 'type',
        })
        providers!: CProvider['type'][];
    }
    const module = await Test.createTestingModule({
        imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
            providers: [{ provide: C_PROVIDER, useClass: C1 }],
        }),
        CustomInjectorModule.forFeature({
            providers: [{ provide: C_PROVIDER, useClass: C2 }],
        }),
        ],
        providers: [P],
        exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const p = app.get<P>(P);
    expect(p.providers).toEqual(['c1', 'c2']);
    await app.close();
    });
    


    다중 일반 및 비동기 공급자와 협력




    interface CProvider {
      type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class C1 implements CProvider {
      type = 'c1';
    }
    @Injectable()
    class C2 implements CProvider {
      type = 'c2';
    }
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER, {
        multi: true,
        propertyName: 'type',
      })
      providers!: CProvider['type'][];
    }
    const module = await Test.createTestingModule({
      imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C1 }],
        }),
        CustomInjectorModule.forFeature({
          providers: [
            {
              provide: C_PROVIDER,
              useFactory: () =>
                new Promise((resolve) => setTimeout(() => resolve(new C2()), 1000)),
            },
          ],
        }),
      ],
      providers: [P],
      exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const p = app.get<P>(P);
    expect(p.providers).toEqual(['c1', 'c2']);
    await app.close();
    


    공급자 배열이 설정되지 않은 경우 오류




    interface CProvider {
      type: string;
    }
    const C_PROVIDER1 = 'C_PROVIDER1';
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER1, {
        multi: true,
        propertyName: 'type',
      })
      providers!: CProvider['type'];
    }
    const module = await Test.createTestingModule({
      imports: [CustomInjectorModule.forRoot()],
      providers: [P],
      exports: [P],
    }).compile();
    const app = module.createNestApplication();
    try {
      await app.init();
      expect(true).toEqual(false);
    } catch (err) {
      expect(err instanceof CustomInjectorError && err.message).toEqual(
        `Providers "C_PROVIDER1" not found!`
      );
      expect(
        err instanceof CustomInjectorError &&
          err.injectedProvidersStorageItem?.token
      ).toEqual(C_PROVIDER1);
    }
    await app.close();
    


    공급자 배열이 설정되지 않은 경우 사용자 지정 오류




    interface CProvider {
      type: string;
    }
    class CustomError extends CustomInjectorError<CProvider> {
      constructor(public override message: string) {
        super(message);
      }
    }
    const C_PROVIDER1 = 'C_PROVIDER1';
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER1, {
        multi: true,
        propertyName: 'type',
        errorFactory: (message: string) => new CustomError(message),
      })
      providers!: CProvider['type'];
    }
    const module = await Test.createTestingModule({
      imports: [CustomInjectorModule.forRoot()],
      providers: [P],
      exports: [P],
    }).compile();
    const app = module.createNestApplication();
    try {
      await app.init();
      expect(true).toEqual(false);
    } catch (err) {
      expect(err instanceof CustomError && err.message).toEqual(
        `Providers "C_PROVIDER1" not found!`
      );
      expect(
        err instanceof CustomError && err.injectedProvidersStorageItem?.token
      ).toEqual(undefined);
    }
    await app.close();
    


    팩토리로 다중 제공자 생성




    interface CProvider {
      type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class C1 {
      name = 'c1';
    }
    @Injectable()
    class C2 {
      name = 'c2';
    }
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER, {
        multi: true,
        propertyName: 'type',
        providerFactory: (data) => ({ type: data.name }),
      })
      providers!: CProvider['type'][];
    }
    const module = await Test.createTestingModule({
      imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C1 }],
        }),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C2 }],
        }),
      ],
      providers: [P],
      exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const p = app.get<P>(P);
    expect(p.providers).toEqual(['c1', 'c2']);
    await app.close();
    


    비동기 팩토리로 다중 제공자 생성




    interface CProvider {
      type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class C1 {
      name = 'c1';
    }
    @Injectable()
    class C2 {
      name = 'c2';
    }
    @Injectable()
    class P {
      @CustomInject<CProvider>(C_PROVIDER, {
        multi: true,
        propertyName: 'type',
        providerFactory: (data) =>
          new Promise((resolve) =>
            setTimeout(() => resolve({ type: data.name }), 1000)
          ),
      })
      providers!: CProvider['type'][];
    }
    const module = await Test.createTestingModule({
      imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C1 }],
        }),
        CustomInjectorModule.forFeature({
          providers: [{ provide: C_PROVIDER, useClass: C2 }],
        }),
      ],
      providers: [P],
      exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const p = app.get<P>(P);
    expect(p.providers).toEqual(['c1', 'c2']);
    await app.close();
    


    응용 프로그램 부트스트랩에서 설정하지 않고 데이터 가져오기에 지연 옵션을 사용하여 다중 공급자를 로드합니다.




    interface CProvider {
        type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class C1 implements CProvider {
        type = 'c1';
    }
    @Injectable()
    class C2 implements CProvider {
        type = 'c2';
    }
    @Injectable()
    class P {
        @CustomInject<CProvider>(C_PROVIDER, {
        multi: true,
        propertyName: 'type',
        lazy: true,
        })
        providers!: CProvider['type'][];
    }
    const module = await Test.createTestingModule({
        imports: [
        CustomInjectorModule.forRoot(),
        CustomInjectorModule.forFeature({
            providers: [{ provide: C_PROVIDER, useClass: C1 }],
        }),
        CustomInjectorModule.forFeature({
            providers: [{ provide: C_PROVIDER, useClass: C2 }],
        }),
        ],
        providers: [P],
        exports: [P],
    }).compile();
    const app = module.createNestApplication();
    // we don't need start application, because providers marked with lazy options will be ignored when the application bootstrap
    // await app.init();
    const p = app.get<P>(P);
    expect(p.providers).toEqual(['c1', 'c2']);
    await app.close();
    });
    


    토큰 공급자를 찾을 수 없는 경우 기본 공급자 사용




    interface CProvider {
        type: string;
    }
    const C_PROVIDER = Symbol('C_PROVIDER');
    @Injectable()
    class P {
        @CustomInject<CProvider>(C_PROVIDER, {
        multi: true,
        propertyName: 'type',
        defaultProvidersValue: [],
        })
        providers!: CProvider['type'][];
    }
    const module = await Test.createTestingModule({
        imports: [CustomInjectorModule.forRoot()],
        providers: [P],
        exports: [P],
    }).compile();
    const app = module.createNestApplication();
    await app.init();
    const providers = app.get<P>(P).providers;
    expect(providers).toEqual([]);
    await app.close();
    });
    

    좋은 웹페이지 즐겨찾기