Skip to main content
Ben Nadel at Angular 2 Master Class (New York, NY) with: Pascal Precht
Ben Nadel at Angular 2 Master Class (New York, NY) with: Pascal Precht ( @pascalprecht )

Understanding The Role Of Static Methods In An Angular 2 Dependency-Injection Context

By on

In the Angular 2 dependency-injection (DI) framework, Angular maps tokens onto singleton instances of JavaScript "classes." This allows us to swap in and out various implementations of a class so long as all of the other classes agree on which DI token is needed to reference the abstract implementation. Each concrete implementation of a the given class token then has to adhere to the interface inherent in the DI token contract. But, classes can have both static and instance methods; so, which of these need to be implemented by a concrete class in a dependency-injection context?

At first, you might think that both static and instance methods are part of the class "contract" in a dependency-injection context. After all, if you're trying to swap in and out various implementations, it's natural to think that the entire topology of the swappable classes needs to be interchangeable.

And, you'd be right - if we were actually dealing with "classes." But, in a dependency-injection framework, like Angular 2, we're not dealing with classes, we're dealing with instances of classes. This is a very important difference. In JavaScript (and therefore in Angular 2), class instances don't include static methods in their public API. As such, the set of static methods exposed on a constructor is not part of the "API contract" bound to each instance created by that constructor.

It might be easier to think about this divergence outside of a dependency-injection framework. So, let's look at the native Array class in JavaScript. While the Array class exposes static methods, like isArray(), those static methods cannot be accessed on each array instance:


 
 
 

 
 Static methods are not exposed on the instances of a class and are therefor enot part of the dependency-injection contract.  
 
 
 

What this means for consumers of the Angular 2 dependency-injection framework is that when you need to implement a given class interface, you only need to implement the instance methods of that class. Since the dependency-injection framework only deals in instances, no injected dependency will ever expose a static method (see epilogue). Therefore, static methods are not part of the contract inherent in a dependency-injection token.

Epilogue: The Angular 2 dependency-injection framework deals primarily with class instances, but not exclusively. As such, it is most certainly possible to make the DI framework provide a class constructor as opposed to a class instance. In that case, the injected value would expose static methods since the injected value is a class and not an instance of a class. But, that's not really relevant to this discussion.

Reader Comments

15 Comments

Hi Ben,

again nice deep overview about more, kind of complex, ng2 behind the scenes concepts.

Providing a class constructor for ng2 DI is a no brainer, because ng2 is so awesome :)

I've created a plunk to demonstrate

http://plnkr.co/edit/z0uYfrJw5yfuFMW7kgHY?p=preview

15,640 Comments

@All,

On Twitter, Darien (@bhathos) pointed out the fact that you can technically gain access to the Constructor "static" methods using the the .constructor property on the class instance. Using the Array example, you could technically do something like:

var a = [];
a.constructor.isArray( "blam" );

.... but, in my opinion, the .constructor property should be treated more like meta-data and less like a property of the instance itself. For example, I think it's fine to assume that the .constructor property can power the "instanceof" operator (and to define the constructor property when outlining your prototype). But, beyond that, I wouldn't really depend on it too heavily.

But, that's just my opinion.

15,640 Comments

@Martin,

Excellent example. For anyone who is not exactly sure what Martin is demonstrating, in his provider collection, he's using:

provide( "FooClass", { useValue: Foo } )

This is telling Angular 2 to use the *CLASS* Foo as the injectable, as opposed to *instantiating* the class Foo and using the *instance* as the injectable. This way, you could use either the static or the instance methods; but, they would be attached, so to speak, to two different injectables.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel