如何使用不污染全局范围的TypeScript类定义AngularJS服务?

Yng*_*sen 36 global-variables angularjs typescript angularjs-service

我正在使用AngularJS和TypeScript.我想使用Typescript类实现AngularJS服务,如下所示:

class HelloService {
    public getWelcomeMessage():String {
        return "Hello";
    }
}

angular.module('app.services.helloService', []).factory('helloService', () => {
    return new HelloService();
});
Run Code Online (Sandbox Code Playgroud)

这将编译为以下javascript代码:

var HelloService = (function () {
    function HelloService() {
    }
    HelloService.prototype.getWelcomeMessage = function () {
        return "Hello";
    };
    return HelloService;
})();

angular.module('app.services.helloService', []).factory('helloService', function () {
    return new HelloService();
});
Run Code Online (Sandbox Code Playgroud)

这会使用变量HelloService污染全局命名空间,这显然是我不想要的.(使用Chrome的控制台我验证了HelloService是一个对象.)如何解决/避免此问题?

我试过了明显的事:

angular.module('app.services.helloService', []).factory('helloService', function () {
    class HelloService { ...} 
    return new HelloService();
});
Run Code Online (Sandbox Code Playgroud)

但这给了我一个编译错误("意外的令牌;预期的'声明'.").

我能想到的一个可能的解决方案是以某种方式使用TypeScript的导入和导出,而这又将使用RequireJS.这可能会将HelloService包装在define函数中,从而避免使用HelloService污染全局范围.但是,我现在不想在我的AngularJS应用程序中使用RequireJS,因为我认为AngularJS足够好用于我的使用,并且它增加了复杂性.

所以,我的问题是,如何使用不污染全局范围的TypeScript类来定义AngularJS服务?

Sly*_*nal 34

2016-05-06:使用ES6样式模块的新示例

静态$inject数组和构造函数与前一个示例保持不变.

唯一的变化是将类拆分为多个文件,并使用ES6模块引入类定义.

/lib/HelloService.ts:

export class HelloService {
    public getWelcomeMessage():String {
        return "Hello from HelloService";
    }
}
Run Code Online (Sandbox Code Playgroud)

/lib/AnotherService.ts:

import {HelloService} from './HelloService';

/**
 * Service that depends on HelloService.
 */
export class AnotherService {

    // Define `HelloService` as a dependency.
    static $inject = ['HelloService'];
    constructor(
        // Add the parameter and type definition.
        public HelloService: HelloService
    ){}

    public getWelcomeMessage():String {
        // Access the service as: `this.HelloService`
        // Enjoy auto-completion and type safety :)
        var helloMsg = this.HelloService.getWelcomeMessage();
        return "Welcome from AnotherService, " + helloMsg;
    }
}
Run Code Online (Sandbox Code Playgroud)

/index.ts:

// Using the services.
import {HelloService} from './lib/HelloService';
import {AnotherService} from './lib/AnotherService';

angular.module('HelloApp', [])
    .service('HelloService', HelloService)
    .service('AnotherService', AnotherService)
    .run(['AnotherService', function(AnotherService: AnotherService){
        console.log(AnotherService.getWelcomeMessage());
    }]);
Run Code Online (Sandbox Code Playgroud)

上一个答案:使用命名空间

Steve Fenton的回答中建立:

要允许依赖注入,请$inject在类上添加静态数组.

有关数组如何工作的信息,请参阅Angular $ injector文档$inject.

依赖项将按照数组给出的顺序注入到构造函数中(并使其适用于缩小).

依赖注入示例:

namespace MyModule {
    /**
     * Angular Service
     */
    export class HelloService {
        public getWelcomeMessage():String {
            return "Hello from HelloService";
        }
    }

    /**
     * Service that depends on HelloService.
     */
    export class AnotherService {

        // Define `HelloService` as a dependency.
        static $inject = ['HelloService'];
        constructor(
            // Add the parameter and type definition.
            public HelloService: MyModule.HelloService
        ){}

        public getWelcomeMessage():String {
            // Access the service as: `this.HelloService`
            // Enjoy auto-completion and type safety :)
            var helloMsg = this.HelloService.getWelcomeMessage();
            return "Welcome from AnotherService, " + helloMsg;
        }
    }
}


// Using the services.
angular.module('app.services.helloService', [])
    .service('HelloService', MyModule.HelloService)
    .service('AnotherService', MyModule.AnotherService)
    .run(['AnotherService', function(AnotherService: MyModule.AnotherService){
        console.log(AnotherService.getWelcomeMessage());
    }]);
Run Code Online (Sandbox Code Playgroud)


Yng*_*sen 14

我应该提供我实际上结束的事情:

module MyModule {
    export class HelloService {
        public getWelcomeMessage():String {
            return "Hello";
        }
    }

    angular.module('app.services.helloService', []).factory('helloService', () => {
        return new HelloService();
    });
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我可以使用

return new HelloService();
Run Code Online (Sandbox Code Playgroud)

代替

return new MyModule.HelloService();
Run Code Online (Sandbox Code Playgroud)

  • 为了简化更多,使用`.service('helloService',HelloService)`而不是`factory`,因为它会为你在构造函数上调用`new`. (23认同)
  • 我认为你甚至可以在课堂上省略`export`陈述.上面显示的代码不需要它,因为您没有从模块外部访问此类.也许我是愚蠢的,只是用TypeScript w/Angular缠绕我的头. (2认同)

Fen*_*ton 6

我有两个解决方案,第一个给你基于类的语法,第二个在全局范围内绝对没有...

您可以通过仅向全局范围添加单个句柄来稍微妥协(如果您希望避免将多个类放在全局范围内,这实际上适用,因为当前您只有一个类).

以下代码仅在全局范围内保留模块.

module MyModule {
    export class HelloService {
        public getWelcomeMessage():String {
            return "Hello";
        }
    }

    export class AnotherService {
        public getWelcomeMessage():String {
            return "Hello";
        }
    }

}

angular.module('app.services.helloService', []).factory('helloService', () => {
    return new MyModule.HelloService();
});

angular.module('app.services.anotherService', []).factory('anotherService', () => {
    return new MyModule.AnotherService();
});
Run Code Online (Sandbox Code Playgroud)

或者,要在全局范围内保留一个东西,您可以避免使用类语法并使用"普通旧JavaScript":

angular.module('app.services.helloService', []).factory('helloService', () => {
    var HelloService = (function () {
        function HelloService() {
        }
        HelloService.prototype.getWelcomeMessage = function () {
            return "Hello";
        };
        return HelloService;
    })();

    return new HelloService();
});
Run Code Online (Sandbox Code Playgroud)