Wednesday, February 18, 2015

Creating Stuff in Angular/TypeScript

Dependency injection is a big piece of Angular. To make it work an object that is created via this dependency injection has to essentially have a dependency injection "signature". This signature is a minification proof description of what should get used when you create an object with DI.

Now when you build a large system you want to develop individual, isolated pieces and you don't want the added overhead of matching these signatures between multiple files. By this I mean you don't want a file defining your module having all your DI signatures that then have to match with your classes. So you want to define the DI signature in your class.

Our project has had somewhat of a sordid history with this. The first pattern was to have the following in a TypeScript class:

public injection(): any[] { return [...,...,ServiceConstructor] }

Then in the module construction file (I am against this concept as noted in other posts) you had this code:

appName.service('ServiceName', Path.MyClass.prototype.injection());

So I hated this. First, you have a function to return a fixed array. Second you use "prototype" when one of the main goals of TypeScript is to abstract away the prototype. So I did a quick modification to this:

public static injection = [...,...,ServiceConstructor];
appName.service('ServiceName', Path.MyClass.injection);

It is a little shorter and a little clearer. It was also a very simple transformation. For awhile I thought this was a good pattern, but it turns out Angular had better way of doing things which makes it a little shorter and it does this by a magic name like so:

public static $inject = [...,...];
appName.service('ServiceName', Path.MyClass);

This is even shorter since Angular knows to check objects for a $inject property. It is succinct and expressive.

Now this is all great when Angular is handling your dependency injection and for many systems this is sufficient, but for designs that get a little more complex you may need to create objects directly. For example, I have a NotificationService that gets notifications from a server. This service is a persistent singleton, but it holds on to a volatile connection (since the connection can down, be reset, or whatever). I want to create the NotificationConnection within my NotificationService since the service part manages the connection part, but the connection can be a singleton and I want to inject standard Angular services into it. So I need to use the DI mechanism like so:

$injector.instantiate(NotificationConnection)

or if I want to pass things in I can do so by creating an object with names that correspond to injection names like so:

$injector.instantiate(NotificationConnection, {events: events})

Having simple patterns for using the injector helps make your life easier.

No comments:

Post a Comment