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:
The type definition for restangular (which I installed with
tsd install restangular --resolve --save
) tells me that the successCallback in the getTimeZones() method is apromiseValue: 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 acceptsany[]
, but when debuggin I see that the successCallback promised value it's not an array of TimeZone[]. It has the properties I expected (code
andname
) 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[]
?Is there any example on how to achieve something similar with TypeScript?
Thank you.
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 fromIService
andArray<any>
) so that I can de-restangularize the response like this:Now everthing seems to be fine and the response is, indeed, a promise of
TimeZone[]