我正在尝试使用DefinatelyTyped($resource
,IResource
和朋友)干净地将Angular自定义IResourceClass
扩展名作为工厂编写为TypeScript类。
根据Misko Hevery资源只有constructor
个函数,因此我希望能够将$resource
定义为具有某些类型安全接口的常规类(INamedEntityResource
或{ {1}})并混合服务定义但我似乎无法在我的NamedEntityResource原型上获得标准类方法以最终出现在工厂实例上。
有没有办法使用INamedEntity
函数执行此操作,还是应该放弃并在纯JavaScript中定义服务?
constructor()
所以这样做的目的是允许我编写一个资源类{},其方法将在我通过HTTP加载的每个资源上进行注释。在这种情况下,我的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);
}
s。
这是迄今为止我能够获得的最接近的解决方案,看起来确实有效,但感觉非常糟糕。
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 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);
}
这是构造函数中的角度svc
服务,当然,您可以在JavaScript中执行此操作,但感觉就像在TypeScript中真的很脏鸭子类型。但是,最后,我可以向$resource
添加方法,它们将出现在从我的HTTP资源加载的所有实体的原型中。
答案 0 :(得分:3)
我一直在寻找答案。它在打字稿文档中。接口可以扩展类。将方法添加到资源实例的解决方案如下:
class Project {
id: number;
title: string;
someMethod(): boolean {
return true;
}
}
export interface IProject extends ng.resource.IResource<IProject>, Project {
// here you add any method interface generated by the $resource
// $thumb(): angular.IPromise<IProject>;
// $thumb(params?: Object, success?: Function, error?: Function): angular.IPromise<IProject>;
// $thumb(success: Function, error?: Function): angular.IPromise<IProject>;
}
export interface IProjectResourceClass extends ng.resource.IResourceClass<IProject> { }
function projectFactory($resource: ng.resource.IResourceService): IProjectResourceClass {
var Resource = $resource<IProject>('/api/projects/:id/', { id: '@id' });
// the key, for this to actually work when compiled to javascript
angular.extend(Resource.prototype, Project.prototype);
return Resource;
}
module projectFactory {
export var $inject: string[] = ['$resource'];
}
我还没有完全测试过,但我已经测试了一下并且有效。
答案 1 :(得分:0)
使用service
而不是factory
注册课程:
servicesModule.service('NamedEntityResource', NamedEntityResource);
免责声明:我的视频介绍了有关angularjs + typescript中服务注册的其他信息:http://www.youtube.com/watch?v=Yis8m3BdnEM&hd=1
答案 2 :(得分:0)
这是我如何在这里使用$ http
module portal{
var app =angular.module('portal',[]);
app.service(services);
}
module portal.services {
export class apiService {
public getData<T>(url?:string): ng.IPromise<T> {
var def = this.$q.defer();
this.$http.get(this.config.apiBaseUrl + url).then((successResponse) => {
if(successResponse)
def.resolve(successResponse.data);
else
def.reject('server error');
}, (errorRes) => {
def.reject(errorRes.statusText);
});
return def.promise;
}
public postData<T>(formData: any, url?:string,contentType?:string): ng.IPromise<T>{
var def = this.$q.defer();
this.$http({
url: this.config.apiBaseUrl + url,
method: 'POST',
data:formData,
withCredentials: true,
headers: {
'Content-Type':contentType || 'application/json'
}
}).then((successResponse)=>{
def.resolve(successResponse.data);
},(errorRes)=>{
def.reject(errorRes);
});
return def.promise;
}
static $inject = ['$q','$http', 'config'];
constructor(public $q:ng.IQService,public $http:ng.IHttpService, public config:interfaces.IPortalConfig) {
}
}
}