Remo H. Jansen
Remo H. Jansen

Reputation: 25009

Angular 2.0 DI can I depend upon abstractions?

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:

enter image description here

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.

enter image description here

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:

enter image description here

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 emitDecoratorMetadatabecomes capable of serialising interfaces.

Upvotes: 1

Views: 180

Answers (2)

koroandr
koroandr

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

Günter Zöchbauer
Günter Zöchbauer

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

Related Questions