Angularjs – How to implement ng.IDirectiveFactory in TypeScript

angularjsangularjs-directivetypescript

I recently updated my angular.d.ts file in my typescript project. I am now getting a typescript compile error in my Directive definitions. I noticed the following in the updated angular.d.ts file:

interface IDirectiveFactory {
    (...args: any[]): IDirective;
}

I am trying to figure out how to implement this interface.

I get this compiler error: Type ng.DirectiveFactory requires a call signature, but type "MyDirective" lacks ones.

This is how my directive looks right now (which used to work fine with older angular.d.ts file):

class MyDirective{
    constructor() {
        var directive: ng.IDirective = <ng.IDirective>{};
        directive.priority = 0;
        directive.restrict = "E";
        directive.scope = {...};
        directive.template = '<div></div>';
        directive.link = {...}
        return directive;
    }
}

And this is where I register the MyDirective class with angular:

angular.module("MyModule", [])
        .directive('myDirective', MyDirective);

The above compiler error makes perfect sense, but how do I implement the (…args: any[]): IDirective signature) ?

Thanks in advance

Best Answer

I know this is an old question, but I came across this problem as well and thought I would share my solution:

class MyDirective implements ng.IDirective {
    priority = 0;
    restrict = 'E';
    scope = {...};
    template = '<div></div>';

    link(scope: ng.IScope
        , element: ng.IAugmentedJQuery
        , attributes: IAttributes
        , controller: any
        , transclude: ng.ITranscludeFunction) {
        ...
    }
}

angular.module("MyModule", [])
    .directive('myDirective', () => new MyDirective());

I like this solution because it allows you to use the full benefits of a TypeScript class.

UPDATE If you want to use this approach to simplify your link function using private class functions or fields, you will need to define your link function slightly differently:

class MyDirective implements ng.IDirective {
    priority = 0;
    restrict = 'E';
    scope = {...};
    template = '<div></div>';

    link = (scope: ng.IScope
        , element: ng.IAugmentedJQuery
        , attributes: IAttributes
        , controller: any
        , transclude: ng.ITranscludeFunction) => {
        ...
    }
}

angular.module("MyModule", [])
    .directive('myDirective', () => new MyDirective());

(note that the link method is here declared as a fat arrow function rather than a class function)

This is because when Angular wires this up, it does so in a way that doesn't preserve the this reference for the class. By defining it with a fat arrow function, the compiled JavaScript will define the function in a way that will preserve the this reference. Otherwise you will get lots of errors trying to run the code.