DEV Community

Cover image for Typescript Inheritance
Tyler Burnett
Tyler Burnett

Posted on

Typescript Inheritance

Inheritance isn't easy

Alike to many OOP languages, unfortunately, inheritance can be a major headache. As much as we would love it to be as easy as a flexible typecast, it's simply not possible. Now there are many ways to overcome this, all have their pros and cons. In this article, I will try my best to cover each case and its application scenarios.

Inheritance via constructor

Personally, this is the roadblock I ran into that eventually spurred this article. After trifling through hours of stack overflow I felt I was getting no closer to my solution

In my mind, there are two reasons why you might end with this approach:
A) Porting JSON data back into functional objects
B) Interpreting foreign Json into a structured typescript object

Now let's talk about the code. For context, Let's say this is our data object in JSON format:

{
  "Name": "Jason",
  "Age": "25",
  "Location": "Australia"
}

And this is the object we hope to merge it into:

class Person {
Name : string;
Age : number;
Location: string;
}

Now there are two ways you can achieve this, you can directly inherit the parsed object via string accessors like such:

someFunction() {
let data = JsonData;
let person = Person(JsonData);
}

...
...
...

class Person {
Name : string;
Age : number;
Location: string;

constructor(object : object) {
this.Name = object['Name'];
this.Age = object['Age'];
this.Location = object['string'];
}

}

But this isn't very elegant, and in my opinion not very flexible. (Neither is it very safe).

Now instead of this, you could add an interface that can directly inherit the information which you then port from. That could look something like this.

someFunction() {
let data = JsonData as JsonMedium;
let person = Person(data);
}

...
...
...

interface JsonMedium {
Name : string;
Age : number;
Location: string;
} 


class Person {
Name : string;
Age : number;
Location: string;

constructor(object : JsonMedium {
this.Name = object.Name;
this.Age = object.Age;
this.Location = object.Location;
}

}

Although its extra code, can save some linting headaches as well as add code manageability, besides this both methods work to their own advantages.

Inheritance via function

Now, this method is quite the alternative, its niche and could be heavily dependant on your functional needs. But if someone was keen enough, they could throw together a reflection based function that could translate variables between objects based on name and type.

Now, unfortunately, I'm the kind of person that wastes their time on trivial things like this, so I might as well share the fruits of my labor.

inheritObject(from : object, to : object) : object {

    // Itterate every object variable name
    Reflect.ownKeys(to).forEach(element => {
      // If the object were casting from has
      // the same variable with the same type
      if (Reflect.has(from, element) && to[element].Type == from[element].Type)
      // Move the variable over
      to[element] = from[element];
    });

    return to;
  }

In my opinion, this code is far from perfect, and could definitely have its flexibility extended. But to describe the fundamentals of this method, this code serves as a good example.

Thats what I know

To be clear, I'm sure there are other alternatives to making this inheritance conundrum easier. If you have any, I'd love to hear them so I can further contribute to this issue. In the meantime, I hope you guys found this helpful.

Happy coding everyone.

Top comments (0)