Restangular with Typescript confusing when 'restangularized' response object

Issue

I am using Angular 1.5.x with TypeScript. For accessing a remote API I use restangular. As a summary this is my scenario:

My API has the following resource http://localhost:53384/api/timezones. Sending a request with the verb GET to that url returns a JSON array:

[
   {
      "code":"Dateline Standard Time",
      "name":"(UTC-12:00) International Date Line West"
   },
   {
      "code":"UTC-11",
      "name":"(UTC-11:00) Coordinated Universal Time-11"
   },
   {
      "code":"Hawaiian Standard Time",
      "name":"(UTC-10:00) Hawaii"
   }
]

Now in my client AngularJs application with TypeScript:

Restangular configuration being restangularProvider: restangular.IProvider

restangularProvider.setBaseUrl("http://localhost:53384/api");

The TimeZone object representation in the client side with typescript

module app.blocks {
    "use strict";

    export class TimeZone {
        public code: string;
        public name: string;
    }
}

Factory(restangular.IService) to wrap the restangular all ‘timezones’ resource

module app.services {
    factory.$inject = ["Restangular"];

    function factory(restangular: restangular.IService): restangular.IElement {
        return restangular.all("timezones");
    }

    angular
        .module("app.services")
        .factory("app.services.TimeZonesRestangular", factory);
}

Service that uses TimeZonesRestangular to wrap its restangular functionality and return chained promises to whoever requests timezones in an asynchronous way

module app.services {
    "use strict";

    export interface IStaticDataService {
        getTimeZones(): ng.IPromise<app.blocks.TimeZone[]>;
    }

    class StaticDataService implements IStaticDataService {
        constructor(private timeZonesRestangular: restangular.IElement) {
        }

        public getTimeZones(): ng.IPromise<blocks.TimeZone[]> {
            return this.timeZonesRestangular.getList()
                .then((timeZones: blocks.TimeZone[]) => {
                    return timeZones;
                }, (restangularError: any) => {
                    throw "Error retrieving time zones. Status: " + restangularError.status;
                });
        }
    }

    factory.$inject = ["app.services.TimeZonesRestangular"];

    function factory(timeZonesRestangular: restangular.IElement): IStaticDataService {
        return new StaticDataService(timeZonesRestangular);
    }

    angular
        .module("app.services")
        .factory("app.services.StaticDataService", factory);
}

And finally in the controller using the service to get the ‘timezones’ asynchronously I have this statement

//..other controller things not relevant for this sample
this.staticDataService.getTimeZones()
      .then((timeZones: blocks.TimeZone[]) => {
            this.timeZones = timeZones;
       });

There are 2 PROBLEMS:

  1. The type definition for restangular (which I installed with tsd install restangular --resolve --save) tells me that the successCallback in the getTimeZones() method is a promiseValue: any[], which is fine because it is indeed an array. I thought it would be an array of TimeZone[] and typescript compiles properly because it accepts any[], but when debuggin I see that the successCallback promised value it’s not an array of TimeZone[]. It has the properties I expected (code and name) but it also has many other things restangular-ish. An object within that array looks like this (plus some functions):

    {  
     "code":"Dateline Standard Time",
     "name":"(UTC-12:00) International Date Line West",
     "route":"timezones",
     "reqParams":null,
     "restangularized":true,
     "fromServer":true,
     "parentResource":null,
     "restangularCollection":false
    }
    

    As per https://github.com/mgonto/restangular/issues/150 it looks as if my response had been “restangularized”. Scary description for somebody new to restangular like myself..
    What interface in restangular type definition should I use to represent the array of restangularized TimeZone[] ?

  2. Is there any example on how to achieve something similar with TypeScript?

Thank you.

Solution

After digging a little bit further I found out that the best way to handle this is by expecting a promised value of type restangular.ICollection (which inherits from IService and Array<any>) so that I can de-restangularize the response like this:

public getTimeZones(): ng.IPromise<blocks.TimeZone[]> {
            return this.timeZonesRestangular.getList()
                .then((restangularizedTimeZones: restangular.ICollection) => {
                    return restangularizedTimeZones.plain();
                }, (restangularError: any) => {
                    throw "Error retrieving time zones. Status: " + restangularError.status;
                });
        }

Now everthing seems to be fine and the response is, indeed, a promise of TimeZone[]

Answered By – diegosasw

Answer Checked By – Gilberto Lyons (AngularFixing Admin)

Leave a Reply

Your email address will not be published.