Issue
Have multiple services, that provide very similar functionality but with some differences:
event-type1
, (event-type2 for second service etc.)MODEL_A
, (MODEL_B for second service etc.),URL_PART_A
, (URL_PART_B for second service etc.),
@Injectable()
export Type1Service extends Socket {
type1Update$ = this.fromEvent<MODEL_A>('event-type1');
constructor() {
super({ url: `${environment.url}/${URL_PART_A}` });
}
}
@Injectable()
export class Type2Service extends Socket {
type2Update$ = this.fromEvent<MODEL_B>('event-type2');
constructor() {
super({ url: `${environment.url}/${URL_PART_B}` });
}
}
@Injectable()
export class Type3Service extends Socket {
type3Update$ = this.fromEvent<MODEL_C>('event-type3');
constructor() {
super({ url: `${environment.url}/${URL_PART_C}` });
}
}
I would like to use generic pattern service by @Inject decorator in components. I tried by export class SocketService<T>
, but have the problem with multiple arguments.
Solution
There's no just injecting a generic service directly that returns a different instance based on the generic parameter. So here are a couple of choices - use injection service or create your own service provider. (After writing a custom service provider answer, the injection tokens just seem so much dead simpler that I removed it.)
Using Injection Tokens
/* Service */
export class TypeService<T> extends Socket {
type1Update$ = this.fromEvent<T>(this.eventType);
constructor(urlPart: string, private eventType: string) {
super({ url: `${environment.url}/${urlPart}` });
}
}
/* InjectionTokens - They can live anywhere. */
export const ModelATypeServiceToken = new InjectionToken<TypeService<ModelA>>(
'TypeService for ModelA',
{ factory: () => new TypeService('urlPartA', 'eventType1'), providedIn: 'root' });
export const ModelBTypeServiceToken = new InjectionToken<TypeService<ModelB>>(
'TypeService for ModelB',
{ factory: () => new TypeService('urlPartB', 'eventType2'), providedIn: 'root' });
/* Component */
constructor (@Inject(ModelATypeServiceToken) private typeASvc: TypeService<ModelA>) {}
In the above example, the TypeService is just a simple generic service with urlPart and eventType as a constructor parameters. Injection tokens are created with default factories, that create unique instances of the TypeService per model type.
While it's not a simple as injecting a Generic service directly like you'd do in C#, it's not so bad to define a token per model. How many models do you have in your application that would require engineering something more complex?
Answered By - Daniel Gimenez