Take a look at the compiled JavaScript and you will see that the casting statement disappears because it is only for compilation. Right now you are telling the compiler that somejson is of type Person . The compiler believes you, but in this case it is not.
Therefore, this issue is a JavaScript issue at runtime.
The main goal to get this to work is to somehow tell JavaScript what the relationship between the classes is. So that...
- Find a way to describe the relationships between classes.
- Create something to automatically map json to classes based on this relationship data.
There are many ways to solve this, but I will give one example from the head. This should help describe what needs to be done.
Let's say we have this class:
class Person { name: string; child: Person; public giveName() { return this.name; } }
And this json data:
{ name: 'John', child: { name: 'Sarah', child: { name: 'Jacob' } } }
To display this automatically as instances of Person , we need to tell JavaScript how these types are related. We cannot use TypeScript-type information because we will lose it after compiling it. One way to do this is to have a static property in the type that describes it. For example:
class Person { static relationships = { child: Person }; name: string; child: Person; public giveName() { return this.name; } }
Then, here is an example of a reusable function that handles creating objects for us based on these relationships:
function createInstanceFromJson<T>(objType: { new(): T; }, json: any) { const newObj = new objType(); const relationships = objType["relationships"] || {}; for (const prop in json) { if (json.hasOwnProperty(prop)) { if (newObj[prop] == null) { if (relationships[prop] == null) { newObj[prop] = json[prop]; } else { newObj[prop] = createInstanceFromJson(relationships[prop], json[prop]); } } else { console.warn(`Property ${prop} not set because it already existed on the object.`); } } } return newObj; }
Now the following code will work:
const someJson = { name: 'John', child: { name: 'Sarah', child: { name: 'Jacob' } } }; const person = createInstanceFromJson(Person, someJson); console.log(person.giveName());
Playground
Ideally, the best way is to use something that really reads TypeScript code and creates an object that maintains class relationships. Thus, we do not need to manually maintain relationships and worry about code changes. For example, right now, refactoring code is a little risky with this setting. I'm not sure that at the moment there is something similar, but it is definitely possible.
Alternative solution
I just realized that I had already answered a similar question with a slightly different solution (although this is not related to the embedded data). You can read it here for some ideas:
JSON class instance for TypeScript?