I came across an issue that stems from the way objects behave in JavaScript/TypeScript that is different than the C# behavior. So I thought I would jot it down for the next time I have this problem...
Defining the class and Http method
Let's say we have an object with title
and tags
properties. In our UI, we want to display those values concatenated together. Rather than store this displayName
property, I would create a synthetic property and return a calculated value:
export class Thing {
public title: string;
public tags: string;
public get displayName(): string {
return `${title} [${tags}]`;
}
}
My Thing object is returned from an Http request.Typescript does allow for declaring the type of the data payload. (In this example, TResponse
represents the type of data returned from the call.)
const sendHttpRequest = async <TResponse>(url: string): Promise<TResponse> {
// snip...
aadClient
.fetch(url, AadHttpClient.configurations.v1, options)
.then((response: HttpClientResponse): Promise<TResponse> => {
return response.json();
})
.then((data: TResponse) => {
resolve(data);
})
.catch((error: Error) => {
reject(error);
});
};
Invoking the sendHttpRequest
method requires a Type, and is also pretty straight-forward:
let data = await sendHttpRequest<Thing>("https://someapi");
Reviewing the response
In C#/.Net, deserializing the response returns an instance of the specified type. I can see three properties on the variable. However, it does not work this way in TypeScript.
The call to response.json()
returns an object. But this is a JavaScript/JSON object. Which is not necessarily my Thing
object. It may look like a Thing, but it certainly does not act like a Thing!
Even though I specified a type for the Http response (in the .Net vocabulary, I "closed the generic type"), JavaScript will not necessarily create an object using the complete definition (called the prototype). So, while TypeScript will happily transpile my code, and JavaScript will execute without errors, trying to access the displayName
property of the returned object results in "undefined."
A typical pattern in .Net would be to use the JsonConverter class to convert JSON to a specific type. But in the above code, there is no explicit conversion to a type. It is simply converting a string to an object.
Resolving the issue
Before I try to access the displayName
property, I need to create an instance of my Thing object. In my scenario, I can simply create and assign values:
let thing = Object.assign(new Thing(), data);
NOTE: There is a lot to understand about Object.assign and inheritance and nested objects. Be sure to do your research!