Search code examples
angularobservableangular-httpclient

Cast angular http response into class


I am trying to cast a response object from an HTTP Post request in my angular project to a Person class that I have defined. I have defined a generic post method in an HTTP Service, and am calling that in my person service with the generic replaced with Person. So, I would think, since I have done that the HTTP response should be a Person, but it's not - it's just an Object. I need it to be a Person because my Person class has some custom logic on it that I need to access. I could write a helper method in my person service, but I feel like this should work - especially since VS Code intellisense says that the response in my component is a Person when I hover my mouse over it.

Here is my code:

http.service.ts

@Injectable()
export class HttpService {
    baseUrl = 'https://baseurl.com';

    constructor(private http: HttpClient) { }

    post<T>(endpointUrl: string, body: any): Observable<T> {
        const fullUrl = this.baseUrl + endpointUrl;
        return this.http
            .post<T>(fullUrl, body)
            .pipe(
                map(response => response as T)
            );
    }
}

person.service.ts

@Injectable()
export class PersonService {

    constructor(private httpService: HttpService) { }

    newPerson(body: Person): Observable<Person> {
        return this.httpService.post<Person>('/people', JSON.stringify(body));
    }
}

person.component.ts

@Component({
    selector: 'app-person',
    templateUrl: './person.component.html',
    styleUrls: ['./person.component.css'],
})
export class PersonComponent {
        person: Person = new Person();

        onSubmit(id: number) {
        if (id == 0) {
            console.log(this.person);                              // Person {id: 0, ...
            console.log(this.person.constructor.name);             // Person
            let body = this.person.fromFormGroup(this.formGroup);

            this.personService.newPerson(body)
                .subscribe(response => {                           // VS Code intellisense says this: (parameter) response : Person
                    this.person = response as Person;
                    console.log(this.person);                      // {id: 72, ...
                    console.log(this.person.constructor.name);     // Object

                    // Trying a different way
                    this.person = <Person>response;
                    console.log(this.person);                      // {id: 72, ...
                    console.log(this.person.constructor.name);     // Object
                })

        }
    }

}

Solution

  • newPerson(body: Person): Observable<Person> {
      return this.httpService.post<Person>('/people', JSON.stringify(body));
    }
    

    The HttpClient.post() method can not return type Person, because JSON responses are just cast to types. The default type is just Object, but you need to create a new instance of Person for each response. If the type was an interface then there would be no problem.

    You can create a new instance of Person and then assign the values to that instance.

    newPerson(body: Person): Observable<Person> {
      return this.httpService.post('/people', JSON.stringify(body)).pipe
        map(value => Object.assign(new Person(), value)
      );
    }