Angular 6 HttpClient return instance of class
Asked Answered
P

1

11

Before angular's new HttpClient was introduced, our objects returned from the http api call could be validated with the instanceof keyword. they no longer can with the HttpClient Module. I'm trying some simple methods but the type checks return false every time. the desired behavior of:

```

getCow() {
    return this.http.get<Cow>(ApiRoute.GET_COW, options)
        .map(res => res as Cow)
        .toPromise()
        .then((c: Cow) => {
            console.log(c instanceof Cow); //this is false
        })
}

```

would return true. does anyone know of a simple way to new up an instance behind the scenes of the http client?

Prescind answered 21/5, 2018 at 15:51 Comment(7)
What exactly is Cow? You need to construct it with new and initialize with cow props. It's not something that Angular or TS can handle for you.Vermouth
The above is just a made up example. For sake of the question Cow is a class with no properties and the default constructor.Prescind
What does res contain then? Does this mean that it can be discarded?Vermouth
How did you create instances of the Cow class before? You should be able to do it the same way.Conner
@estus bad example I suppose. Lets say Cow is a class with one property, public sound: string; and res is an object with one property, a string called sound equal to 'moo'. I guess in the end I'm asking why duck typing fails me here after saying its a cow. After all it looks and sounds like a cow.Prescind
Duck typing won't fail you if you do duck typing. See this example https://mcmap.net/q/1017597/-auto-skip-properties-not-belonging-to-the-type-in-typescript , as it was mentioned there you can check if all Point2DDefinition props exist in an object and object values are of same type as Point2DDefinition values. This would result in duck typing at runtime+. But you don't do duck typing. instanceof does a specific thing, it checks if object prototype chain descends from Cow, basically cow.__proto__ === Cow.prototype. It's an opposite of duck typing (cow typing?)Vermouth
I don't consider any of the solutions on StackOverflow to be a comprehensive solution to the problem. So, I created an npm package angular-http-deserializer for this: npmjs.com/package/angular-http-deserializer#usageWestleigh
V
13

TypeScript uses structural typing, i.e. c object doesn't have to be an instance of Cow class to conform to Cow type.

TypeScript types exist only at compilation time and don't affect JS output in any way (with the exception of emitted types which are used for Angular DI). as Cow asserts that res conforms to Cow type, while instanceof Cow expects that c is an instance of Cow class. Since Cow wasn't instantiated, cow instanceof Cow is false.

A class should be designed to support hydration (possibly via constructor parameters) and be instantiated explicitly:

class Cow {
  sound: string;
}

return this.http.get<Cow>(ApiRoute.GET_COW, options)
    .map(res => Object.assign(new Cow(), res as Cow))
    .toPromise()
    .then((c: Cow) => {
        console.log(c instanceof Cow);
    })

If some logic is needed to construct Cow instance from plain object (validation, nested object construction), this can be done in class constructor or separate helper function (e.g. Cow static method).

Vermouth answered 22/5, 2018 at 14:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.