angularjs - 在 TypeScript 中扩展 AngularJS $resource 工厂

标签 angularjs typescript

我正在尝试使用 DefinatelyTyped 干净地编写 Angular 自定义 $resource 扩展作为工厂作为 TypeScript 类。 (IResourceIResourceClass 等)。

根据Misko Hevery资源只是构造函数函数,因此我希望能够将我的$resource定义为具有一些类型安全接口(interface)(INamedEntityResourceINamedEntity) 并混合服务定义,但我似乎无法在我的 NamedEntityResource 原型(prototype)上获取标准类方法以最终出现在工厂实例上。

有没有办法使用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 加载的每个资源上进行注释。在本例中,是我的 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);
}

诀窍是;

  1. 将我想要的服务方法提升到基类中,因为在调用我的 constructor() 函数时 this.prototype 尚未初始化。
  2. 返回 svc ,它是来自构造函数的 Angular $resource 服务,当然你可以在 JavaScript 中执行此操作,但感觉就像在 TypeScript 中进行肮脏的鸭子打字.
  3. 为了获取 svc.prototype 上的方法,我直接从我的基类扩展它。这特别令人讨厌,因为这意味着每次创建实例时都要设置原型(prototype)。
  4. 这个 sh** 三明治的最后一个刺鼻的香气是我必须在构造函数上调用 super() 来获取我要丢弃的实例,只是为了让它编译。<​​/li>

但是,最后,我可以向 NamedEntityResourceBase 添加方法,它们将出现在从我的 HTTP 资源加载的所有实体的原型(prototype)中。

最佳答案

我一直在寻找这个问题的答案。它在 typescript 文档中。接口(interface)可以扩展类。向资源实例添加方法的解决方案如下:

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'];
}

我还没有完全测试,但我已经测试了一些并且可以工作。

关于angularjs - 在 TypeScript 中扩展 AngularJS $resource 工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21819698/

相关文章:

javascript - 在不完全重新加载第二个 iframe 的情况下打开两个 iframe

javascript - 将图像数据存储在 cookie 中

node.js - 多个 swaggerUi 与一个 express 应用程序

javascript - jQuery 智能菜单在 Angularjs 中不起作用

angularjs - 通过分组查询减少 http 请求量

javascript - Angular 未检测到我的指令

typescript - 为什么 TypeScript 无法检查函数的返回类型

javascript - Webpack 代码分割破坏了 block 之间的 instanceof

typescript :在类构造函数中使用 `this` 类型

javascript - 如何使用类型捕获无效的序列化数据输入