Provide Dynamic services using string values

Viewed 19

I'm working on a new library. What I'm trying to achieve here is to give the user the ability to provide any service he wants based on my base service interface, and then I'll use it internally in my library.

Base Service:

export interface MyBaseServiceDataService {
  getData(): Promise<string[]>;
}

Injector and Factory:

export function dataServiceProviderFactory<T extends MyBaseServiceDataService>(type: { new(): T; }): T {
  return new type();
}

export const PROJECT_OPTIONS: InjectionToken<ProjectOptions> =
  new InjectionToken<ProjectOptions>("PROJECT_OPTIONS");


export interface ProjectOptions {
  dataServices?: Record<string, MyBaseServiceDataService>;
  validationServices?: Record<string, Type<MyBaseServiceDataService>>;
}

How I'm planning to use the above code, the user will create a new service like this:

@Injectable()
export class OptionDataService implements MyBaseServiceDataService {

  async getData(): Promise<string[]> {
    return Promise.reject("Not implemented")
  }
}

and then provide blow code in his module:

  providers: [
    {
      provide: PROJECT_OPTIONS,
      useValue: <ProjectOptions>{
        dataServices: {
          options: dataServiceProviderFactory(OptionDataService)
        }
      }
    }]

internally I will call it using my service.

@Injectable()
export class LoaderService {

  private options: ProjectOptions = {}

  constructor(@Optional() @Inject(PROJECT_OPTIONS) injector: ProjectOptions) {
    if(injector)
      this.options = injector
  }

  getDataService(serviceName: string): Promise<string[]> {
    if (!this.options.dataServices)
      return Promise.reject("Data services provider is not provided")
    if (this.options.dataServices[serviceName] === undefined)
      return Promise.reject(`Service ${serviceName} is not provided`)
    return this.options.dataServices[serviceName].getData()
  }
}

Everything is working fine, but I found an issue if the user tries to provide an external service like HttpClient on his own service, the factory is not accepting any constructor,

@Injectable()
export class OptionDataService implements MyBaseServiceDataService {

  constructor(private http: HttpClient) {
    console.log(http);
  }

  async getData(): Promise<string[]> {
    return Promise.reject("Not implemented")
  }
}

even though I changed my factory to something like this

export function dataServiceProviderFactory<T extends Type<MyBaseServiceDataService>>(type: T, ...args: any[]): MyBaseServiceDataService {
  return new type(...args);
}

the instance of HttpClient will be undefined on the service, I'm expecting to receive HttpClient instance from dependency injection, so what I'm missing?

0 Answers
Related