I've read that the new Angular's HttpClient can perform TypeChecking, based on that I write the following code
post(path: string, body: Object = {}): Observable<ValorTest> {
return this.http.post<ValorTest>(path, JSON.stringify(body))
.map((data: ValorTest) => {
console.log(typeof data); // Why console displays 'data' as object instead of ValorTest?
console.log(data instanceof ValorTest); // outputs: false
console.log(data); // outputs (no type displayed in Chrome's console): {codigo: "INF00001", estado: "Success"}
})
.pipe(catchError(this.formatErrors));
}
I'm receiving a JSON that matchs with my model class (ValorTest).
Question: why the console.log displays the type of data as object instead of ValorTest ?
If you're just doing typechecking / assertion, you can use instanceof. If you actually need to print the name of the class, you can try data.constructor.name:
class TestClass {}
var instance = new TestClass();
console.log(typeof instance);
// Expected output: "object"
console.log(instance.constructor.name);
// Expected output: "TestClass"
if (instance instanceof TestClass) {
console.log("instance is TestClass");
}
// Expected output: "instance is TestClass"
As for the why: typeof only works with JavaScript's built in data types, such as string, boolean, object, etc. If you look at the way TypeScript transpiles to JavaScript, you can make sense of why at runtime JavaScript only knows that your instance is an "object".
Updated
This will only work on instances that are created with the new class() constructor. The HttpClient is not actually creating an instance of your class for you here -- it's basically just allowing you (for development purposes) to specify with TypeScript the kind of data you expect to receive in the response. As far as I know, the HttpClient does nothing to ensure (at runtime) that the response data actually meets those expectations. If you require strong type checking at runtime, you would probably need to write your own type guard function.
So if you had a class like this:
class TestClass {
prop: string;
constructor() { }
method(): void {}
}
You could write a type guard like this:
function isTestClass(obj: TestClass | object): obj is TestClass {
// add whatever type checking logic you need here
return (<TestClass>obj).method !== undefined &&
(<TestClass>obj).prop !== undefined;
}
And check your data at runtime:
var obj_a = { prop: "" },
obj_b = { prop: "", method: null };
console.log(isTestClass(obj_a));
// Expected output: false
console.log(isTestClass(obj_b));
// Expected output: true
I might make the type guard function a static method of my class.
Also, as an aside, you might consider using an interface for your response data instead of a class -- mostly because it might help drive the intuition that the data you've received may or may not have the implementation you expect.
More on user-defined type guards at: https://www.typescriptlang.org/docs/handbook/advanced-types.html