使用 typescript 的 IResourceClass 扩展 angularjs 的 $resource

Posted

技术标签:

【中文标题】使用 typescript 的 IResourceClass 扩展 angularjs 的 $resource【英文标题】:Extending $resource of angularjs using IResourceClass of typescript 【发布时间】:2014-03-08 06:00:38 【问题描述】:

我正在使用 Asp.Net Web API 和 AngularJS 开发 SPA。我还使用 TypeScript 来获取静态类型。所以,我添加了DefiniteTyped angularjs。

因为我正在使用 RESTfull 服务。我想过使用 $resource 的 angularjs。现在我 $resource 没有任何 PUT http 方法的内置方法。所以我决定添加我自己的如下。

var employees = $resource('/api/employee/:id',id:'@id',"update": method: "PUT", isArray:false ;

现在,如您所见,在普通的 AngularJS 中很容易做到。我想通过 TypeScript 路由并定义扩展 IResourceClass 的自定义接口。这个接口的文档是这样解释的。

// 具有默认操作的每个资源的基类。 // 如果你为资源定义了新的动作,你需要 // 扩展此接口并将 ResourceClass 类型转换为它。

我真的不知道如何扩展这个接口。它不断出现一些关于语法的错误。有人能解释一下如何扩展这个接口并添加 Update 方法,然后在我的控制器上调用 PUT 方法。

【问题讨论】:

请让我知道我的回答是否有帮助,或者您是否仍被困在 cmets 中。谢谢。 AngularJS 绝对类型页面上有一些关于 TypeScript 使用 $resource 的非常有用的文档 - github.com/DefinitelyTyped/DefinitelyTyped/tree/master/… 【参考方案1】:

首先定义您的模型,即描述您的员工的界面。

// Define an interface of the object you want to use, providing it's properties
interface IEmployee extends ng.resource.IResource<IEmployee>

    id: number;
    firstName : string;
    lastName : string;

然后创建一个描述您将创建的资源的接口。

// Define your resource, adding the signature of the custom actions
interface IEmployeeResource extends ng.resource.IResourceClass<IEmployee>

    update(IEmployee) : IEmployee;

创建EmployeeResource 工厂:

var myApp = angular.module('myApp', ['ngResource']).factory('EmployeeResource', 
    ['$resource', ($resource : ng.resource.IResourceService) : IEmployeeResource => 

        // Define your custom actions here as IActionDescriptor
        var updateAction : ng.resource.IActionDescriptor = 
            method: 'PUT',
            isArray: false
        ;

        // Return the resource, include your custom actions
        return <IEmployeeResource> $resource('/api/employee/:id',  id: '@id' , 
            update: updateAction
        );

    ]);

将您的EmployeeResource 注入控制器:

myApp.controller('TestCtrl', ['$scope', 'EmployeeResource', ($scope, Employee : IEmployeeResource) => 

    // Get all employees
    var employees : Array<IEmployee> = Employee.query();

    // Get specific employee, and change their last name
    var employee : IEmployee = Employee.get( id: 123 );
    employee.lastName = 'Smith';
    employee.$save();

    // Custom action
    var updatedEmployee : IEmployee = Employee.update( id: 100, firstName: "John" );
]);

创建一个新员工实例:

您可以通过newEmployeeResource 工厂创建IEmployee 类型的实例。

myApp.controller('TestCtrl', ['$scope', 'EmployeeResource', ($scope, Employee : IEmployeeResource) => 

    var myEmployee : IEmployee = new Employee( firstName: "John", lastName: "Smith");
    myEmployee.$save();

所以在上面的例子中,我们将IEmployeeResource 注入为Employee。然后我们可以new这个对象创建一个IEmployee

【讨论】:

如果您发布答案,请确保它们至少可以编译。我认为 [$resource, ($resource : ng.resource.IResourceService) : IEmployeeResource => 必须是 ['$resource', ($resource : ng.resource.IResourceService) : IEmployeeResource => 注意引号。 @LocalJoost 我已经修正了小错字。如果您发现拼写错误,请随时自行编辑,这就是 SO 方式。 请不要告诉我如何在您相对较新的社区中回答问题,这很粗鲁。 @LocalJoost 它对我有用。在 promise 被解决时,它可能看起来是空的,之后它被填充。这就是 AngularJS 的工作原理。您的 Employee.query(, (d) =&gt; var a = d; ) 有效,因为它正在使用结果调用您已解析的函数。这是设计使然。 很棒的答案!非常详细。我在这个问题上苦苦挣扎;这个答案显示了我需要修复的 TS 架构中的一些潜在缺陷。感谢您的彻底回答和您投入的时间。 @MushinNoShin 我添加了创建新IEmployee 的示例。这是由newing 在注入的工厂实例上完成的。【参考方案2】:

我完全同意 Scott 的回答:https://***.com/a/21786326/2677975

我确实有一个补充: 在我的项目中,我创建了类ServiceModel&lt;T&gt;,它实现了接口IActionDescriptor

module Common.ApiService 
    export class HttpHeaders 
        'Content-Type': string;
        Accept: string;
    

    export class ServiceModel<T> implements ng.resource.IActionDescriptor 
        public method: string = 'GET';
        public params: T;
        public isArray: boolean = false;
        public url: string;
        public headers: HttpHeaders = new HttpHeaders()
     

然后,我可以在控制器中设置方法,就像 Scott 所做的那样,但是现在,IDE 将在标头(以及稍后的参数)上进行类型完成

export interface IProfileServiceResource extends ng.resource.IResourceClass<IProfileDataModelDef> 
    SaveProfileImage(profileImageUri: Profile.Model.UserProfileModel): ng.resource.IResource<Array<any>>;


export class ProfileApiService 
    implements Common.ApiService.IApiServiceBase<IProfileServiceResource> 

    public SaveProfileImage: Common.ApiService.ServiceModel<Profile.Model.UserProfileModel>;

    constructor()     
        this.SaveProfileImage = new Common.ApiService.ServiceModel<Profile.Model.UserProfileModel>();
        this.SaveProfileImage.method = "POST";
        this.SaveProfileImage.url = "/api/Profile/SaveProfileImage";
        this.SaveProfileImage.headers["Content-Type"] = 'application/json';

我将此作为附加答案,因为它仅用于为 headersparams 提供类型。

【讨论】:

以上是关于使用 typescript 的 IResourceClass 扩展 angularjs 的 $resource的主要内容,如果未能解决你的问题,请参考以下文章

【Unity】Resource加载浅析

typescript使用 TypeScript 开发 Vue 组件

使用来自使用旧版 Typescript 确定类型的 Typescript 定义文件

使用TypeScript中的TypeScript库

typescript 使用传递Type的Typescript继承

优雅的在vue中使用TypeScript