Cross Referencing With Extended Classes In TypeScript
Last Updated :
16 Aug, 2024
TypeScript has features like inheritance, allowing you to extend classes. When dealing with more complex applications, you might encounter cases where classes need to reference each other or even work in a cross-referenced manner. This is common in systems where different classes are interdependent, such as a relationship between different entities or modules.
Basics of Class Extension
In TypeScript deriving from a base class involves simple class extension where a derived class inherit properties, and methods of its parent.
Example: In this example we have Dog extending Animal so that the former inherits name property and speak function from Animal, besides this the Dog adds fetch function of its own, when myDog.speak() is called then “Rex barks” will be displayed because the method has been overridden, the fetch method is unique to the Dog class and outputs “Rex is fetching.”
JavaScript
class Animal {
constructor(public name: string) { }
speak(): void {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name);
}
speak(): void {
console.log(`${this.name} barks.`);
}
fetch(): void {
console.log(`${this.name} is fetching.`);
}
}
const myDog = new Dog("Rex", "Labrador");
myDog.speak(); // Rex barks.
myDog.fetch(); // Rex is fetching.
Output
Rex barks.
Rex is fetching.
Cross-Referencing Inherited Members
In TypeScript there are mechanism to ensure that types of base class and derived class match as well as they can be used correctly in cross-referencing.
1. Accessing Base Class Properties and Methods
You can directly access properties and methods of base class using derived class, the type system of TypeScript guarantees that these members have correct types.
Example: In this example, Cat is a class and it extends Animal, it inherits from Animal its name property and speak method, in Cat, makeSound invokes a speak inherited from Animal, if myCat.makeSound() is called, it prints “Whiskers makes a sound”, which means that base class method was successfully accessed.
JavaScript
class Animal {
constructor(public name: string) { }
speak(): void {
console.log(`${this.name} makes a sound.`);
}
}
class Cat extends Animal {
constructor(name: string) {
super(name);
}
makeSound(): void {
this.speak(); // Accessing base class method
}
}
const myCat = new Cat("Whiskers");
myCat.makeSound(); // Whiskers makes a sound.
Output
Whiskers makes a sound.
2. Overriding Methods
TypeScript ensures that when you override methods in any derived classes it checks if their signatures are compatible with those of base classes ones, the keyword override should be used to specify that a method is overriding another one belonging to the base object.
Example: In this example Dog class overrides speak method from the Animal class, the override keyword ensures that method signatures match and that the base method is being replaced, when myDog.speak() is called, it outputs "Dog barks," demonstrating the overridden behavior.
JavaScript
class Animal {
speak(): void {
console.log("Animal sound.");
}
}
class Dog extends Animal {
override speak(): void {
console.log("Dog barks.");
}
}
const myDog = new Dog();
myDog.speak(); // Dog barks.
Output
Dog barks.
3. Type Compatibility with Polymorphism
Type system of TypeScript facilitate polymorphism whereby base class type can refer to derived class instances and this guarantees that methods and properties are used correctly across various class types.
Example: In this example makeAnimalSpeak is a function that accepts an Animal type and calls its speak method, both Dog and Cat extend Animal and provide their specific implementations of speak, when makeAnimalSpeak(myDog) is called, it outputs "Rex barks," and when makeAnimalSpeak(myCat) is called, it outputs "Whiskers meows" showcasing polymorphism and correct method invocation based on instance type.
JavaScript
class Animal {
constructor(public name: string) { }
speak(): void {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name);
}
speak(): void {
console.log(`${this.name} barks.`);
}
fetch(): void {
console.log(`${this.name} is fetching.`);
}
}
class Cat extends Animal {
constructor(name: string) {
super(name);
}
speak(): void {
console.log(`${this.name} meows.`);
}
}
function makeAnimalSpeak(animal: Animal): void {
animal.speak();
}
const myDog = new Dog("Rex", "Labrador");
const myCat = new Cat("Whiskers");
makeAnimalSpeak(myDog); // Rex barks.
makeAnimalSpeak(myCat); // Whiskers meows.
Output
Rex barks.
Whiskers meows.
Advanced Cross-Referencing Techniques
1. Abstract Classes and Methods
Abstract classes define methods that must be implemented by derived classes, this ensures derived classes provide particular implementations of abstract methods.
Example: In this example Shape class is abstract and defines an abstract method getArea that must be implemented by derived classes, Rectangle class extends Shape and provides an implementation for getArea, when myRectangle.printArea() is called, it outputs "The area is 200," showing that abstract method has been correctly implemented.
JavaScript
abstract class Shape {
abstract getArea(): number;
printArea(): void {
console.log(`The area is ${this.getArea()}`);
}
}
class Rectangle extends Shape {
constructor(private width: number, private height: number) {
super();
}
getArea(): number {
return this.width * this.height;
}
}
const myRectangle = new Rectangle(10, 20);
myRectangle.printArea(); // The area is 200
Output
The area is 200
2. Generics with Inheritance
Generics can be used in conjunction with inheritance to create flexible and reusable class structures, TypeScript generics are very influential in this language because they help you to manufacture components, functions and classes that can be used with different types of data, these generics make it possible for us to design type safe class hierarchies that can be adjusted even when combined with inheritance.
Example: In this example Repository class is a generic class that can store items of any type T, UserRepository class extends Repository with a specific type User, when a User instance is added to userRepository, it is correctly stored and retrieved by demonstrating how generics and inheritance can work together to create flexible data structures.
JavaScript
class Repository<T> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
get(index: number): T | undefined {
return this.items[index];
}
}
class User {
constructor(public name: string) { }
}
class UserRepository extends Repository<User> { }
const userRepository = new UserRepository();
userRepository.add(new User("GeeksForGeeks"));
console.log(userRepository.get(0)?.name);
Output
GeeksForGeeks
Similar Reads
How to Extend abstract class with Generics in Typescript ?
In Typescript, an abstract class is the base class that is inherited by other classes without having to define its members. Generic is the feature with which you can create a variable that represents a type in classes, functions, and type aliases that don't need to define the types that they use exp
3 min read
How to Create Nested Classes in TypeScript ?
In TypeScript, you can create nested classes using different methods. We will discuss about three different approaches to creating nested classes in TypeScript. These are the approaches: Table of Content By defining nested classes inside a classBy using the namespacesBy using the modulesBy defining
3 min read
How to use Interface with Class in TypeScript ?
In TypeScript, interfaces define the structure that classes must adhere to, ensuring consistent object shapes and facilitating type-checking. Interfaces declare properties and methods without implementations, serving as contracts for classes to implement.Classes use the implements keyword to adhere
3 min read
TypeScript - Generic Functions and Generic Classes
Generics in TypeScript enable functions and classes to work with multiple data types while ensuring type safety. Generic functions provide reusable logic that adapts to various inputs, while generic classes help define flexible and type-safe structures. Generic FunctionsA generic function allows you
2 min read
What is Declaration Merging in Typescript ?
In Typescript, the term "declaration merging" refers to the compiler combining two declarations with the same name into a single definition. Both of the initial declarations are present in this combined definition. It is possible to merge Interfaces, namespaces and enums and so on but classes cannot
3 min read
Function Overloading With Generics In TypeScript
TypeScript has the ability to overload functions which means multiple signatures may be defined for one single function, this comes in handy when you want a function to behave in a certain way based on the provided parameters. In this article, we will be looking at how function overloading is done u
4 min read
TypeScript Generic Classes
Generics in TypeScript allow us to create reusable and type-safe components. Generic classes help in defining a blueprint that can work with different data types without sacrificing type safety. They enable better code reusability and flexibility by allowing us to define type parameters that will be
5 min read
Explain Type assertions in TypeScript
In TypeScript, type assertions allow developers to override the compiler's inferred type, informing it of the specific type of a value. Type assertions are purely compile-time constructs and do not alter the runtime behavior of the code. They are particularly useful when interfacing with APIs or thi
4 min read
TypeScript Assertion functions
TypeScript Assertion functions are nothing but the functions that allow us to mainly create the custom type guards that assert the type of a value on our specific criteria. The most suitable use of Assertion Functions is when we are working with the more complex data structures. Syntax:function asse
3 min read
How to implement class constants in TypeScript ?
In this article, we will try to understand how to create several class constants (properties with constant values) in TypeScript with the help of certain code examples for better concept understanding as well as clarification. Let us first understand quickly how we may create a class in TypeScript w
3 min read