如何使用具有构造函数参数的 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 工厂的主要内容,如果未能解决你的问题,请参考以下文章