change - Angular 2 interfaz inyectable?
change title angular 4 (1)
Hoy me encontré con algo que no pensé que me causaría problemas.
En Java y Spring, puedo declarar dos beans que implementan una interfaz dada, mientras que en otra clase donde se inyectan solo trabajo con la interfaz; De hecho, esto es lo que amo con IoC: realmente no tienes que saber con qué objeto estás trabajando, solo que es amable .
Entonces, en mi pequeño programa Angular2 / Typescript, estaba tratando de hacer lo mismo:
webapp.module.ts:
...
import { WebAppConfigurationService } from ''./app/services/webapp.configuration.service'';
@NgModule({
...
providers: [WebAppConfigurationService]
})
export class AppModule { }
tnsapp.module.ts:
...
import { TnsConfigurationService } from ''./services/tns.configuration.service'';
@NgModule({
...
providers: [TnsConfigurationService]
})
export class AppModule { }
Ambos módulos usan un proveedor diferente: TnsConfigurationService
o WebAppConfigurationService
.
Sin embargo, estos dos servicios @Injectable
implementan la misma interfaz:
configuration.interface:
export interface IConfigurationService {
...
}
Finalmente, en uno de mis componentes, utilizo el inyectable proporcionado por uno de estos módulos que te mostré al principio:
import { IConfigurationService } from ''./configuration.interface'';
export class HeroesService {
constructor(private configurationService: IConfigurationService) { }
}
Mi expectativa era que este último componente se inyectara con el servicio correcto, a pesar de que el parámetro solo define explícitamente la interfaz. Por supuesto, aparece un error ("Error: no se pueden resolver todos los parámetros para HeroesService")
Ahora, no espero una solución fácil para esto, ya que suena como una falta arquitectónica. Pero tal vez alguien me puede señalar un diseño alternativo?
Para que un proveedor sea inyectado, debe registrarse como proveedor. No hay un proveedor IConfigurationService
. Y no puede ser un proveedor, porque las interfaces no existen en el código JS compilado.
La práctica común para las interfaces que se supone deben usarse como tokens de proveedor es ser clases abstractas:
abstract class ConfigurationService { ... }
@Injectable()
class WebAppConfigurationService extends ConfigurationService { ... }
...
providers: [{ provide: ConfigurationService, useClass: WebAppConfigurationService }]
...
Esta receta es comúnmente utilizada por Angular 2, por ejemplo, la clase abstracta NgLocalization
y la implementación concreta de NgLocaleLocalization
.