【问题标题】:How can I define an AngularJS service using a TypeScript class that doesn't pollute the global scope?如何使用不会污染全局范围的 TypeScript 类定义 AngularJS 服务?
【发布时间】:2023-03-11 13:19:02
【问题描述】:

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

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

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

这将编译为以下 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();
});

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

我尝试了显而易见的:

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

但这给了我一个编译错误(“意外的令牌;预期的'语句'。”)。

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

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

【问题讨论】:

    标签: angularjs global-variables typescript angularjs-service


    【解决方案1】:

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

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

    唯一的改变是将类拆分成多个文件并使用 ES6 模块来拉入类定义。

    /lib/HelloService.ts:

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

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

    /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());
        }]);
    

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

    Steve Fenton's answer构建:

    要允许依赖注入,请在您的类上添加一个静态 $inject 数组。

    请参阅Angular $injector documentation,了解$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());
        }]);
    

    【讨论】:

    • (yourSolution) => {comment = '完美、明亮、简单、直接';返回“干杯”; }
    【解决方案2】:

    我应该提供我实际完成的工作:

    module MyModule {
        export class HelloService {
            public getWelcomeMessage():String {
                return "Hello";
            }
        }
    
        angular.module('app.services.helloService', []).factory('helloService', () => {
            return new HelloService();
        });
    }
    

    这样我就可以用了

    return new HelloService();
    

    而不是

    return new MyModule.HelloService();
    

    【讨论】:

    • 为了更简单,请使用.service('helloService', HelloService) 而不是factory,因为它会为您调用构造函数上的new
    • 我认为你甚至可以在课堂上省略export 声明。上面显示的代码不需要它,因为您没有从模块外部访问此类。也许我很愚蠢,只是使用带有 Angular 的 TypeScript 来解决我的问题。
    • @SunilD。您通常会导出由服务实现的接口。这样,您可以在注入服务时进行类型检查和代码完成/智能感知等。您也可以为此使用导出的类,但我相信使用接口作为类型更干净:)
    【解决方案3】:

    我有两个解决方案,第一个为您提供基于类的语法,第二个在全局范围内绝对没有任何内容...

    您可以通过仅向全局范围添加一个句柄来稍微妥协(如果您有多个类并且希望避免将其放入全局范围中,因为目前您只有一个类)。

    以下代码仅将模块留在全局范围内。

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

    或者,为了不在全局范围内留下任何东西,您可以避免使用类语法并使用“plain old JavaScript”:

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

    【讨论】:

    • 依赖注入呢?
    • 在下面查看我的回答 (stackoverflow.com/a/25540282/81723),了解如何使用这种方法处理依赖注入。
    • Yngvar Kristiansen 对 Nathan 的评论的回答实际上更好
    • 投反对票,因为您当然可以在 TypeScript 中使用 IIFE,这意味着您不必引入任何全局名称。类语法和命名空间污染是正交的。另外,如果您要注册课程,请使用angular.service 方法。这就是它的用途。创建类实例的工厂完全没有必要,而且会导致代码混乱。
    【解决方案4】:

    这是我正在遵循的方法:

    module HelperServices {
        export class helloService {
           sayHelloWorld: () => string;
            constructor() {
                this.sayHelloWorld = () => {
                    return "Hello World";
                }
            }
        }
    }
    

    就这么简单..

    【讨论】:

    • 但这不适用于依赖注入,您的其他模块将显式依赖该类,因此您不能轻松地模拟它。请参阅 angularjs 文档,了解他们选择使用依赖注入的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 2021-01-12
    • 2018-08-30
    • 2018-11-29
    • 2021-10-04
    • 2014-04-09
    • 2021-07-14
    相关资源
    最近更新 更多