Constructing an object using a type of a generic?

Viewed 2141

I'm working with a public RESTful API that returns objects that have fields of URLs that point to more info. I'd like to wrap these fields in an object that indicates what they point to so I created an object like so:

class APIResource<T> {
    url: string;
}

Where T describes what the url should return. T isn't actually even used by the object as far as typescript is concerned but it helps me know what I should expect. I'm working with Angular2 but please note that what I'm trying to do is not Angular specific. I have an API class where I can request a URL and provide a type to convert it to:

class Person {
  name: string;
  age: number;

  constructor(obj: any) {
    // all Constructable<T> classes will
    // have a constructor that looks
    // exactly like this
    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());
  });
}

Basically, I make an ajax request to get json from the API, I pass it through the constructor of my type and return the object. It would be used like this:

var person: Person;
api.get('/person/1/', Person).subscribe(p => person = p);

This works if I have the constructor to pass in, but what I'd like to do is write up a getResource<T>(resource: APIResource<T>): Observable<T> function so I could do something like this:

var res: APIResource<Person> = { url: '/person/1/' };
var person: Person;
api.getResource(res).subscribe(p => person = p);

But so far nothing has worked. Right now I can't get the type T out of APIResource to use my current method. I've tried modifying APIResource:

class APIResource<T> {
  url: string;

  getType(): T {
    return T;
  }
}

Or

class APIResource<T extends Constructable<T>> {
  url: string;

  fetch(): T {
    // just a test to see if tsc complains
    // which it does with "cannot find name T"
    var obj: any = {};
    return new T(obj);
  }
}

But neither of them work. I know the type information is gone once it's javascript. Instead of the type moving around, I think I'd be able to work with moving around the constructor but I don't think I can do that with generics.

Is there anyway to make this work with generics?

I'm using typescript 1.8.7

1 Answers
Related