Why isn't the response to my http.get typed?

453 views Asked by At

Here is what I think is a very familiar pattern for angular & typescript:

import { Component } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs';



@Component({
    selector: 'some-selector'
})
class someComponent{

    someObject: someClass;
    someSum: number;
    someError: string;
    
    constructor(private _someService: SomeService) 
    {}
    
    getSomeObject(): void {
        this._someService.getSomeObject().subscribe<someClass>({
            next: results => {
                this.someObject = results;
                this.someSum = this.someObject.sum();
            },
            error: err => this.someError = err,
            complete: () => {}
        )
    }
}



class SomeService {
    constructor(private _http: HttpClient) 
    {}

    getSomeObject(): Observable<someClass> {
        return this._http.get<someClass>("");
    }
}



class someClass {
    prop_1:number;
    prop_2:number;
    sum():number{
        return this.prop_1 + this.prop_2
    }
}

I have intentionally left out error catching and other stuff because I want to keep this simple (and really want the answer with as minimal an explanation as possible). Seems to me that this code has everything that it needs to be able to convert the results of the http.get into the class specified, and yet if I were to debug this component with Chrome's F12 inspector, I get an error like the following:

core.js:4081 ERROR TypeError: _this.someObject.someSum is not a function

... when it gets to the part "this.someSum = someObject.sum();"

So what else do I need to do to be able to properly deserialize the results of the http.get so it will behave like the object it is typed to be?

1

There are 1 answers

0
DBallantyne On

Apparently, its not that automatic. Read the section "Requesting a typed response" from https://angular.io/guide/http

Specifying the response type is a declaration to TypeScript that it should treat your response as being of the given type. This is a build-time check and doesn't guarantee that the server will actually respond with an object of this type. It is up to the server to ensure that the type specified by the server API is returned.

... and then...

To specify the response object type, first define an interface with the required properties. Use an interface rather than a class, because the response is a plain object that cannot be automatically converted to an instance of a class.

... and finally,

When you pass an interface as a type parameter to the HttpClient.get() method, you can use the RxJS map operator to transform the response data as needed by the UI. You can then pass the transformed data to the async pipe.

So it looks like I need to manually and explicitly convert the incoming object into the interface or class that I want (and RxJS map is one way to do that).