Will Angular inject more than one instance of a generic Service if it is invoked across Component constructors using different Types?
I have a lot of Services that are going to provide the same functionality for different classes that all inherit from the same base class. I'd like to use Typescript's generic pattern MyService<T extends BaseClass>
to handle this.
But I don't know how it jives with Angular's injector:
Code:
@Injectable export class MyService<T> { ... } @Component export class ComponentA { constructor(alphaService MyService<Alpha>) {} <--Instance 1 } @Component export class ComponentB { constructor(betaService MyService<Beta>) {} <----Instance 2? } @Component export class ComponentA1 { constructor(alphaService MyService<Alpha>) {} <---Instance 1? }
Is this legal? Does the injector know to create two instances of MyService?
The @Injectable() decorator defines a class as a service in Angular and allows Angular to inject it into a component as a dependency. Likewise, the @Injectable() decorator indicates that a component, class, pipe, or NgModule has a dependency on a service. The injector is the main mechanism.
Constructor injection: Here, it provides the dependencies through a class constructor. Setter injection: The client uses a setter method into which the injector injects the dependency. Interface injection: The dependency provides an injector method that will inject the dependency into any client passed to it.
The @Injectable decorator aims to actually set some metadata about which dependencies to inject into the constructor of the associated class. It's a class decorator that doesn't require parameters. Without this decorator no dependency will be injected...
The @Injectable() decorator specifies that Angular can use this class in the DI system. The metadata, providedIn: 'root' , means that the HeroService is visible throughout the application. Next, to get the hero mock data, add a getHeroes() method that returns the heroes from mock. heroes.
This is a simple solution:
// service and models export class User { firstName: string } export class Admin { lastName: string } @Injectable() export class GenericService<T>{ item: number = Math.random(); GetAll(): Array<T> { let output = []; console.log(this.item); // each instance has own value return output; } }
Then set your service in module through useFactory:
providers: [ { provide: 'UserService', useFactory: () => (new GenericService<User>()) }, { provide: 'AdminService', useFactory: () => (new GenericService<Admin>()) }, ],
and inject your service with @Inject decorator:
constructor( @Inject('UserService') private userService: GenericService<User>, @Inject('AdminService') private adminService: GenericService<Admin> ) { }
Keep in mind it is better to use InjectionToken ( OpaqueToken is deprecated) for your provider token.I have used string just for simplicity.
An additional instance won't be created for generics. As it is stated here, reflect-metadata
(which is used by Angular 2 decorators to support TypeScript type annotations) can't obtain this kind of information:
TypeScript only emits type metadata for types available at run time, and does not emit type aliases, interfaces, or generics (as they do not have a JavaScript representation).
The amount of MyService
instances depends on whether MyService
was defined as component's provider or it was inherited from parent injector.
In the code above, ComponentA
and ComponentA1
can inherit MyService
provider from parent injector, ComponentB
can get a new instance with providers: [MyService]
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With