如何在TypeScript中实现ng.IDirectiveFactory

时间:2014-08-09 05:12:28

标签: angularjs angularjs-directive typescript

我最近在我的打字稿项目中更新了我的angular.d.ts文件。我现在在指令定义中得到一个打字稿编译错误。我在更新的angular.d.ts文件中注意到以下内容:

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

我想弄清楚如何实现这个界面。

我收到此编译错误:输入ng.DirectiveFactory需要调用签名,但键入" MyDirective"缺乏。

这是我的指令现在看起来的样子(以前用于较旧的angular.d.ts文件可以正常工作):

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;
    }
}

这是我用angular:

注册MyDirective类的地方
angular.module("MyModule", [])
        .directive('myDirective', MyDirective);

上面的编译错误很有道理,但我如何实现(... args:any []):IDirective签名??

提前致谢

3 个答案:

答案 0 :(得分:12)

我知道这是一个老问题,但我也遇到了这个问题,并且认为我会分享我的解决方案:

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());

我喜欢这个解决方案,因为它允许您使用TypeScript类的全部好处。

<强>更新 如果您想使用此方法来使用私有类函数或字段来简化链接函数,则需要稍微不同地定义链接函数:

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());

(请注意,此处将链接方法声明为胖箭头函数而不是类函数)

这是因为当Angular将其连接起来时,它会以不保留类的this引用的方式进行连接。通过使用胖箭头函数定义它,编译的JavaScript将以保留this引用的方式定义函数。否则,在尝试运行代码时会出现很多错误。

答案 1 :(得分:9)

directive()的旧签名曾经是......

directive(name: string, directiveFactory: Function): IModule;

将一个类用作Function是合法的。但是this commit将签名更改为:

directive(name: string, directiveFactory: IDirectiveFactory): IModule;

IDirectiveFactory是一个返回IDirective的函数,因此directive()不再接受directiveFactory参数的类。将其更改为...

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

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

答案 2 :(得分:2)

Joe Skeen提供了一个完全符合我要求的答案。

还有另外一个人Aaron Holmes为他制定了类似的解决方案,其中包括对处理链接的一些改进。

http://blog.aaronholmes.net/writing-angularjs-directives-as-typescript-classes/#comment-2111298002

与Joe的上述答案相反,不是直接引用ng.IScope,而是使用接口,您可以用TypeScript方式定义自己的范围变量(intellisense!)

将链接逻辑移动到构造函数似乎是一种更好的方法。

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

为:

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

以下是Aaron的完整示例:

module MyModule.Directives  
{
    export interface IMyScope: ng.IScope
    {
        name: string;
    }

    export class MyDirective
    {
        public link: (scope: IMyScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes) => void;
        public template = '<div>{{name}}</div>';
        public scope = {};

        constructor()
        {
            MyDirective.prototype.link = (scope: IMyScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes) =>
            {
                scope.name = 'Aaron';
            };
        }

        public static Factory()
        {
            var directive = () =>
            {
                return new MyDirective();
            };

            directive['$inject'] = [''];

            return directive;
        }
    }
}

一个陷阱:你需要使用冒号&#34;:&#34;而不是&#34; =&#34;如果您将链接逻辑移动到构造函数中,则在声明链接时。