如何使用具有构造函数参数的 TypeScript 类定义 AngularJS 工厂

Posted

技术标签:

【中文标题】如何使用具有构造函数参数的 TypeScript 类定义 AngularJS 工厂【英文标题】:How can I define an AngularJS factory using TypeScript class that has constructor parameters 【发布时间】:2014-07-26 05:25:44 【问题描述】:

我想写一个 TypeScript 类,在构造函数中获取一个“前缀”参数,这个类还需要访问 LogService 注入。

使用纯 javascript 你应该这样做:

angular.module('myModule', []).factory('LogWithPrefixFactory', ['LogService', function(LogService) 
    var LogWithPrefixFactory = function(prefix) 
        this.prefix = prefix;
    

    LogWithPrefixFactory.prototype.log = function(txt) 
        // we have access to the injected LogService
        LogService.log(this.prefix, txt);
    

    return LogWithPrefixFactory;
]);

所以当你将这个工厂注入到一个控制器时,你可以像这样多次启动它(不需要注入LogService):

angular.module('myModule').controller('Ctrl', function(LogWithPrefixFactory) 
    var foo = new LogWithPrefixFactory("My PREFIX");
    var foo = new LogWithPrefixFactory("My OTHER PREFIX");

你会如何在 TypeScript 类中定义这个工厂? TypeScript 类不能在函数内部定义... 此类应该可以访问 LogService,但它无法在其中一次注入中获取它。

【问题讨论】:

相关话题:***.com/questions/24620275 【参考方案1】:

以下是实现此目的的一种方法:

class LogWithPrefixFactory 
    static LogService;
    constructor(prefix) 
        this.prefix = prefix;
    

    log = function(txt) 
        // we have access to the injected LogService
        LogService.log(this.prefix, txt);
    


angular.module('myModule', []).factory('LogWithPrefixFactory', ['LogService', function(LogService) 
    LogWithPrefixFactory.LogService = LogService;
    return LogWithPrefixFactory;
]);


angular.module('myModule').controller('Ctrl', function(LogWithPrefixFactory) 
    var foo = new LogWithPrefixFactory("My PREFIX");
    var foo = new LogWithPrefixFactory("My OTHER PREFIX");
);

理性:您实际上希望在 LogWithPrefixFactory 中有一个静态属性(在 JS 中使用闭包),并且您希望它来自 Angular。

【讨论】:

这是一个很好的解决方案!但科斯给出了更好的方法。因为他的解决方案是通过注入而不是 const 使课程看起来与常规课程相同。 这里没有常量。只有静态的。静态只是意味着类的所有实例共享相同的非实例引用(实际上与服务的工作方式相同)。这里唯一的区别是静态注入器不是返回所有实例共享的静态服务,而是有一个没有注入器的静态服务。 我认为这个答案更好,因为它是您要求的工厂。【参考方案2】:

至少有 2 个选项。

第一个选项,让LogWithPrefixFactory 提供一个方法getInstance 来返回前缀记录器。

module services 
  class LogService 
    $window: any;

    constructor($window: any) 
      this.$window = $window;
    

    log(prefix: string, txt: string) 
      this.$window.alert(prefix + ' :: ' + txt);
    
  
  angular.module('services').service('LogService', ['$window', LogService]);


  export interface ILog 
    log: (txt) => void;
  

  export class LogWithPrefixFactory 
    logService: LogService;

    constructor(logService: LogService) 
      this.logService = logService;
    

    getInstance(prefix: string): ILog 
      return 
        log: (txt: string) => this.logService.log(prefix, txt);
      
    
  

  angular.module('services').service('LogWithPrefixFactory', ['LogService', services.LogWithPrefixFactory]);

可以在控制器中使用,如:

this.log1 = logWithPrefixFactory.getInstance("prefix1");
this.log2 = logWithPrefixFactory.getInstance("prefix2");

完整的 plunker here.

第二个选项(类似于另一个答案),给Angular另一个函数用作构造函数,它手动处理LogService构造函数注入(我个人不喜欢static)。

angular.module('services').service('LogWithPrefixFactory', ['LogService', function(logService) 
    return function LogWithPrefixFactory(prefix) 
      return new LogWithPrefix(prefix, logService);
    ;
]);

可以在控制器中使用,如:

this.log1 = new LogWithPrefixFactory("prefix1");
this.log2 = new LogWithPrefixFactory("prefix2");

甚至:

this.log1 = LogWithPrefixFactory("prefix1");
this.log2 = LogWithPrefixFactory("prefix2");

LogWithPrefixFactory 被注入到控制器中,但它不是 TypeScript 类的构造函数,它是在“手动”注入 LogService 之后返回类的实际实例的中间函数。

完整的 plunker here.

注意:这些 plunker 在浏览器上同步编译 typescript。我只在 Chrome 上测试过。不能保证他们会工作。最后,我手动添加了一小部分 angular.d.ts。完整文件非常大,我的代理不允许大型 POST。

【讨论】:

是的,用另一个只获取所需参数的函数包装它就是我需要的。 为什么是这些服务而不是工厂?【参考方案3】:

我就是这样做的

 namespace app 
             let app =angular.module('foo',[]);
               app.factory(factories);//for registering whatever is there in factories namespace

      

 namespace app.factories 


 export class fooFactory 

    static $inject = ['fooHelperService']
    constructor(fooHelperService: services.fooHelperService) 

        return 

            fooFunc: () => 

               return 'hellow world'
            
        
    
 


【讨论】:

我得到:构造函数签名的返回类型必须可分配给类的实例类型。类型 fooFunc:() => 字符串不可分配给类型“fooFactory”。对象字面量只能指定已知属性,而 fooFunc 不存在于类型 fooFactory【参考方案4】:

这对我有用。

    namespace Services
    
      export class MyService
      
        constructor( protected $someService :any )
        
          return this;
        
      
    
    angular.module( 'myModule', [] ).factory( Services );

【讨论】:

【参考方案5】:

我已经实现了如下

module Dashboard 
    export class LayoutServiceFactory 
        static $inject = ["$q", "$http"];
        private q: ng.IQService;
        private http: ng.IHttpService;

        constructor(private $q: ng.IQService, private $http: ng.IHttpService) 
            this.q = $q;
            this.http = $http;
        

        getDataFromServer(serviceUrl) 
            var deferred = this.q.defer();
            this.http.get(serviceUrl, null)
                .then(response => 

                    deferred.resolve((response) as any);

                );
            return deferred.promise;
        

        static factory() 
            var instance = ($q: ng.IQService, $http: ng.IHttpService) =>
                new LayoutServiceFactory($q, $http);
            return instance;
        
    

    appModule.factory("LayoutService", LayoutServiceFactory.factory());

【讨论】:

【参考方案6】:

您可以创建一个允许您定义工厂构造函数的类型:

// Defining the factory

// THIS IS THE IMPORTANT PART!!
export type SelectorFactory = new (config: any) => Selector;

export class Selector 

    constructor(protected config: any, protected $http: ng.IHttpService) 
        // do some stuff
    


angular.module('app')
    .factory('Selector', ($http: ng.IHttpService) => 
        // This is what the factory looks like to the end user
        return (config: any) => 
            return new Selector(config, $http);
        ;
    );

// Using the factory
export class SampleCtrl 
    constructor(public SelectorFactory: SelectorFactory) 
        let config =  op: 1 ;

        let selector: Selector = new SelectorFactory(config);
    

【讨论】:

这个错误是:“错误TS4081:导出的类型别名'SelectorFactory'有或正在使用私有名称'Selector' 试试把class Selector改成export class Selector吧?

以上是关于如何使用具有构造函数参数的 TypeScript 类定义 AngularJS 工厂的主要内容,如果未能解决你的问题,请参考以下文章

Typescript构造函数和继承

typescript 从子类调用的构造函数参数推断类型

TypeScript系列教程11函数的使用

TypeScript 构造函数中解构参数属性

TypeScript 构造函数中解构参数属性

如何使用 Typescript 使用自定义方法实现类数组类?