You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
TypeScript interfaces for Dependency Injection #135
In strongly typed languages such as Java or C# we are used to program to an interface.
It allows loosely coupled components and also it allows easier unit testing with mock implementations of the interface (contract).
In TypeScript the interfaces have some interesting features.
structural typing which is "duck typing" inference of interface, even if the class of the object it not marked with it.
ambient declarations which allow you to describe 3rd party API with an interface, after the fact of the creation.
therefore the TS class could explicitly or implicitly implement multiple interfaces. Therefore interface could not be substituted by abstract class. Specially with prototype inheritance of underlying JavaScript.
interfaces in typescript are compile time only construct, useful for compiler to warn you that the (argument) doesn't meet the (API) expectation.
The fact that interfaces do not exist in form of IIFE/class as product of TypeScript compilation is the root of problem, how to use it as the DI marker/handle.
Possible solutions:
generate dummy class for each interface, but do not try to cast to it (whatever it means in JavaScript). Benefit is that IIFE could contain RTTI, downside TypeScript compiler would have to implement this. Would the RTTI of classes which explicitly implemented the interface know about it ? Would there be class.GetInterfaces():type[] ?
capture just the interface name as string and use it as DI handle.
allow for manual annotation of dependencies
More about DI + interfaces vs autowiring with dependencies by class
DI is implementation of IoC pattern. The goal is to externalize the knowledge about composition and implementation of the contract.
Autowiring of injection of specific class is just special case of IoC.
The general case of DI with interfaces needs to be configured explicitly in order to choose the correct implementation of the interface.
Therefore I think we need a way how to register which implementation of interface would be injected.
In many DI frameworks people use fluent API of the DI container to configure it. Sample below is Microsoft Unity which uses RTTI of C# generics for the capture.
just class registration container.RegisterType<InvoicesService>();
class as implementation of interface container.RegisterType<IInvoicesService, InvoicesService>();
sometimes the interface type is not granular enough and we need name as well container.RegisterType<IInvoicesService, InvoicesService>("Czech");
sometimes the implementation is statefull and we need lifetime container.RegisterType<IInvoicesService, InvoicesService>(new ContainerControlledLifetimeManager());
sometimes the singletons need scope, for example per request. There are 2 approaches child container or scoped resolve operation.
More about intended usage:
In strongly typed languages we impose type validating compiler on our-self because the codebase is too big to remember it all.
In this case we are interested to continue usage of TypeScript, which bring this quality to JavaScript.
So if this feature is not easily doable as extension of TS compiler, we would need to find easy way how to achieve same result with manual annotation.
Hope this helps, sorry if I'm not up-to-speed with all details or visions of Angular 2.0 or di component.
-- Pavel
generate dummy class for each interface, but do not try to cast to it (whatever it means in JavaScript). Benefit is that IIFE could contain RTTI, downside TypeScript compiler would have to implement this. Would the RTTI of classes which explicitly implemented the interface know about it ? Would there be class.GetInterfaces():type[] ?
The syntax for this should already be supported with
var injector = new Injector([
Car,
bind(Engine).toClass(CyclicEngine)
]);
Is there an actual Action Item here? I think we already support this so I don't think there is anything to do.
You can register which implementation of an interface should be injected using bind(Engine).toClass(CyclicEngine) or bind(Engine).toFactory(() => new CyclicEngine()).
new Injector([Engine]) is just syntax sugar for new Injector([bind(Engine).toClass(Engine)]).
Activity
mhevery commentedon Nov 4, 2014
@vsavkin
Our current thinking is to go with
The syntax for this should already be supported with
Is there an actual Action Item here? I think we already support this so I don't think there is anything to do.
pavelsavara commentedon Nov 5, 2014
Is there unit test where I could have look at it ?
vsavkin commentedon Nov 5, 2014
@pavelsavara
bind(Engine).toClass(CyclicEngine)orbind(Engine).toFactory(() => new CyclicEngine()).new Injector([Engine])is just syntax sugar fornew Injector([bind(Engine).toClass(Engine)]).mhevery commentedon Nov 6, 2014
Closing since I believe this is covered.
pavelsavara commentedon May 6, 2015
This doesn't work very well in typescript 1.5beta, see microsoft/TypeScript#3060
mhevery commentedon May 8, 2015
The issue is that Types don't have a reference at runtime. But I believe MS will solve it. Nothing for Angular to do here.
angular-automatic-lock-bot commentedon Sep 6, 2019
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.