Lets say I have
class Foo {
bar: string;
public doSomething() {}
}
In my service I'm getting array of those from a server:
this.http.get<Foo[]>(...)
This works, I'm getting all the expected values. BUT when I take one of the objects I got and try to invoke doSomething() on it, I get an error saying that foo (which is of type Foo) doesn't have method doSomething().
It appears that while http.get correctly parsed JSON and assigned all the properties of my objects, it didn't bother with setting up proper prototypes for them, so essentially they are Foos in name only, they are missing all the methods of Foo.
Is that normal or am I doing something wrong? Thank you.
Effectively. In the end, you're just parsing JSON, and the result of parsing JSON are just plain JavaScript objects, never custom classes. this.http.get<Foo[]>
is just a hint for the compiler, but the generic parameter does not really do anything. It doesn't convert one object in another, not does it give them types.
As an advice, you should never use classes when typecasting the result of calls to services or getting objects from localStorage
, sessionStorage
and such. You should use interfaces instead, without methods.
However, it is possible to achieve what you want, if you really need your objects to be of class Foo
and have the doSomething
method:
this.http.get<Foo[]>(...).do(items => items.forEach(item => Object.setPrototypeOf(item, Foo.prototype)));
This will give every object the correcto prototype. However, this has a performance penalty, as changing the prototype of created objects messes with browser optimization, so do it under your own risk.
Another option would be to give Foo
a constructor:
class Foo {
constructor(item: Foo) {
Object.assign(this, item);
}
bar: string;
public doSomething() {}
}
Now:
this.http.get<Foo[]>(...).pipe(map(items => items.map(item => new Foo(item)))).subscribe(...);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With