Reputation: 25009
I've been reading the Angular 2.0 docs about dependency inversion and I've been looking also at some online examples.
My understanding is that the @injectable
decorator uses the TypeScript compiler with the emitDecoratorMetadata
flag to create metadata that is used to resolve dependencies. Take for example the following class:
The TypeScript compiler uses emitDecoratorMetadata
to declare via metadata that the DataService
class has a constructor argument with type Http
.
Once we have declared the dependencies of a class using @Injectable
we can indicate that it needs to be injected into some components using the Provides
option in the @App
or @Component
decorators.
I'm aware of the behaviour of emitDecoratorMetadata
and I know that it cannot emit metadata for interfaces. Therefore, I assume that I cannot depend upon IHttp
instead of Http
:
Is my assumption correct? Can I depend “Depend upon Abstractions. Do not depend upon concretions.” or is that something that is not possible at the moment? I assume this will be fixed as soon as the emitDecoratorMetadata
becomes capable of serialising interfaces.
Upvotes: 1
Views: 180
Reputation: 11
If you are using TypeScript, I have a solution for you.
I am not using Angular 2.0, but we developed similiar DI library (intakejs). The problem is TS compiler emit reflection metadata only for classes, not for interfaces (they are treated like "object").
Hopefully, they would add such functionality further, but nowdays we are using hack based on TypeScript's declaration merging feature. The idea is that you can declare interface, and merge it with string or some other runtime id like this:
export interface IMyInjectable {
foo(): string;
}
export const IMyInjectable = 'MyInjectable';
Let's assume you have implementation of that interface:
@Injectable('MyInjectable')
class MyInjectable implements IMyInjectable {
foo(): string { return 'hello' }
}
Then you can depend upon abstraction in your consumer class:
class MyConsumer {
@Inject(IMyInjectable)
private myInjectable: IMyInjectable;
}
I hope this little trick will solve your problem.
Upvotes: 1
Reputation: 657741
Currently you need a type, a string name or an OpaqueToken
as key for providers.
Interfaces are not supported because the information is not available at runtime. If this gets added, I'm sure DI will support them (it's already supported in Dart).
Upvotes: 3