【发布时间】:2014-03-16 04:41:08
【问题描述】:
我正在尝试使用DefinatelyTyped(IResource、IResourceClass 和朋友)将 Angular 自定义 $resource 扩展作为 TypeScript 类干净地编写为工厂。
根据Misko Hevery 资源只是constructor 函数,所以我希望能够将我的$resource 定义为具有一些类型安全接口(@987654328@ 或INamedEntity)的常规类并混合服务定义但我似乎无法让我的 NamedEntityResource 原型上的标准类方法最终出现在工厂实例上。
有没有办法用 constructor() 函数来做这件事,还是我应该放弃并只用纯 JavaScript 定义服务?
declare module EntityTypes {
interface INamedEntity { }
}
module Services {
export interface INamedEntitySvc {
Name(params: {}, successCallback: (data: any, headers: any) => void, errorCallback: (data: any, headers: any) => void): EntityTypes.INamedEntity;
Clear(params: {}, value: EntityTypes.INamedEntity, successCallback: (data: any, headers: any) => void, errorCallback: (data: any, headers: any) => void): EntityTypes.INamedEntity;
}
// WILL have correct interface definition for the resource
export interface INamedEntityResource extends NamedEntityResource, INamedEntitySvc { }
export class NamedEntityResource {
// #1 DOESN'T WORK - These are on NamedEntityResource.prototype but don't end up on svc
public someMethod() { }
public someOtherMethod() { }
constructor($resource) {
var paramDefaults = {
};
var svc: INamedEntitySvc = $resource(getUrl(), paramDefaults, {
Name: <any>{ method: "GET", params: { action: "Name" } },
Clear: <any>{ method: "PATCH", params: { action: "Clear" }, headers: { 'Content-Type': 'application/json' } },
});
// THIS WORKS - but it's not a NamedEntityResource
svc["prototype"].someMethod = function () { }
svc["prototype"].someOtherMethod = function () { }
return <any>svc;
// #1 DOESN'T WORK THOUGH
return; // doesn't pick up methods on prototype
// #2 THIS DOESN'T WORK EITHER
NamedEntityResource["prototype"] = angular.extend(this["prototype"] || {}, svc["prototype"]);
return this;
}
}
// Registration
var servicesModule: ng.IModule = angular.module('npApp.services');
servicesModule.factory('NamedEntityResource', NamedEntityResource);
}
进一步
所以这样做的目的是允许我编写一个资源类{},该类的方法将在我通过 HTTP 加载的每个资源上进行注释。{}在这种情况下,我的INamedEntitys。
这是迄今为止我能得到的最接近的解决方案,它看起来确实有效,但感觉真的很糟糕。
module Services {
export interface INamedEntitySvc {
Name(params: {}, successCallback: (data: any, headers: any) => void, errorCallback: (data: any, headers: any) => void): EntityTypes.INamedEntity;
Clear(params: {}, value: EntityTypes.INamedEntity, successCallback: (data: any, headers: any) => void, errorCallback: (data: any, headers: any) => void): EntityTypes.INamedEntity;
}
// WILL have correct interface definition for the resource
export interface INamedEntityResource extends NamedEntityResource, INamedEntitySvc { }
export class NamedEntityResourceBase {
public someMethod() { }
public someOtherMethod() { }
}
// extend our resource implementation so that INamedEntityResource will have all the relevant intelisense
export class NamedEntityResource extends NamedEntityResourceBase {
constructor($resource) {
super(); // kind of superfluous since we're not actually using this instance but the compiler requires it
var svc: INamedEntitySvc = $resource(getUrl(), { }, {
Name: <any>{ method: "GET", params: { action: "Name" } },
Clear: <any>{ method: "PATCH", params: { action: "Clear" }, headers: { 'Content-Type': 'application/json' } },
});
// Mixin svc definition to ourself - we have to use a hoisted base class because this.prototype isn't setup yet
angular.extend(svc["prototype"], NamedEntityResourceBase["prototype"]);
// Return Angular's service (NOT this instance) mixed in with the methods we want from the base class
return <any>svc;
}
thisWontWork() {
// since we never actually get a NamedEntityResource instance, this method cannot be applied to anything.
// any methods you want have to go in the base prototype
}
}
// Registration
var servicesModule: ng.IModule = angular.module('npApp.services');
servicesModule.factory('NamedEntityResource', NamedEntityResource);
}
诀窍是;
- 将我想要的服务上的方法提升到一个基类中,因为 this.prototype 在我的 constructor() 函数被调用时还没有初始化。
- 返回
svc,这是来自构造函数的有角度的$resource服务,您当然可以在JavaScript 中执行此操作,但在TypeScript 中感觉就像是非常脏的鸭子类型。 - 为了获得 svc.prototype 上的方法,我直接从我的基类扩展了它。这尤其令人讨厌,因为这意味着每次创建实例时都要设置原型。
- 这个 sh** 三明治的最终刺鼻气味是我必须在构造函数上调用 super() 来处理我要丢弃的实例,以便编译它。
不过,最后,我可以向NamedEntityResourceBase 添加方法,它们将出现在从我的 HTTP 资源加载的所有实体的原型中。
【问题讨论】:
标签: angularjs typescript