Currently, I am dealing with a public RESTful API that provides objects containing URL fields leading to additional information. I wanted to encapsulate these fields within an object indicating their purpose so I devised the following structure:
class APIResource<T> {
url: string;
}
In this setup, T
specifies the expected return from the url
. Although not utilized by TypeScript, T
serves as a reference for what to anticipate. While my work revolves around Angular2, it's important to note that this concept is not Angular-exclusive. My approach involves an API class where I can request a URL and specify a type for conversion:
class Person {
name: string;
age: number;
constructor(obj: any) {
// all Constructable<T> classes will
// share a constructor structured in
// the same way
Object.assign(this, obj);
}
print() {
console.log(this.name + ' is ' + this.age);
}
}
interface Constructable<T> {
new (obj: any): T;
}
public get<T>(url: string, type: Constructable<T>): Observable<T> {
return this.http.get(url).map(result => {
return new type(result.json());
});
}
The process entails making an AJAX call to retrieve JSON data from the API, then passing it through the designated constructor before returning the object. To implement this, you would execute the following:
var person: Person;
api.get('/person/1/', Person).subscribe(p => person = p);
While this works when a specific constructor is provided, my goal is to create a
getResource<T>(resource: APIResource<T>): Observable<T>
function to enable operations like the one below:
var res: APIResource<Person> = { url: '/person/1/' };
var person: Person;
api.getResource(res).subscribe(p => person = p);
Unfortunately, my attempts thus far have been unsuccessful. I am facing challenges accessing the type T
from APIResource
to integrate it into my existing method. Various modifications to APIResource were attempted:
class APIResource<T> {
url: string;
getType(): T {
return T;
}
}
And also:
class APIResource<T extends Constructable<T>> {
url: string;
fetch(): T {
var obj: any = {};
return new T(obj);
}
}
However, neither of these adjustments proved successful. I understand that TypeScript loses the type information once it transitions to JavaScript. Instead of moving the type around, I believe manipulating the constructor might be feasible, although challenging with generics.
Is there a solution to making this work effectively with generics?
Note: Currently utilizing typescript 1.8.7