TypeScript Extend Interface, Merge and Intersection Types

In TypeScript, an interface can extend another interface using the extends keyword. Similar to inheritance in other programming languages, interface extension allows:

  • creating a new interface based on an existing one
  • inheriting the properties and methods of the base/parent interface
  • adding new properties and methods
  • overriding existing properties and methods if necessary
interface Color { ... }
interface Shape { ... }

// Extending an interface
interface Circle extends Shape { ... }

// Extending multiple interfaces
interface ColoredCircle extends Shape, Color { ... }

// Intersection Type
type ColoredCircle = Color & Circle;

This tutorial discusses the interface extension, interface merging, and intersection types in TypeScript with simple examples.

1. Extending an Interface

An interface may be marked as extending another interface by adding the ‘extends’ keyword after its name (referred to as the derived interface), followed by the name of the interface to extend (referred to as the base interface). After extending, the derived interface ensures that it has all the properties and methods of the base interface.

In the following example, Shape is the base interface which is extended by Circle. The Circle is called the derived interface.

// Base interface
interface Shape {
  color: string;
  area(): number;
}

// Extended interface
interface Circle extends Shape {
  radius: number;
}

We can create objects of type Circle and use the properties and methods from both interfaces:

const circle: Circle = {
  color: 'red',
  radius: 5,
  area() {
      return Math.PI * this.radius ** 2;
  }
};

console.log(circle.area()); // Output: 78.53981633974483
console.log(circle.color); // Output: red

2. Overridden Properties and Methods

A derived interface may override, or replace, properties from its base interface by declaring the property again with a different type. Still, the TypeScript’s type checker will enforce that an overridden property must be assignable to its base property.

It does so to ensure that instances of the derived interface type stay assignable to the base interface type.

For example, let’s look at the Shape and Circle interfaces. We can override the ‘color’ property in Circle interface but its value in Circle must satisfy its value in Shape as well.

// Base interface
interface Shape {
  color: string;
  area(): number;
}

// INCORRECT
interface Circle extends Shape {
  color: string | number; // Override color property allowing a number also
  radius: number;
}

// CORRECT
interface Circle extends Shape {
  color: 'red' | 'blue'; // Override color property with a more specific type
  radius: number;
}

3. Extending Multiple Interfaces

TypeScript allows us to extend from multiple interfaces, also. To do so, the derived interface should specify all the interface names separated by commas, after the extends keyword. The derived interface will receive all members from all base interfaces.

In the following example, ColoredCircle interface extends from Shape and Circle interfaces, both.

// Base interface representing a shape
interface Shape {
  color: string;
}

// Interface representing a circle
interface Circle {
  radius: number;
  area(): number;
}

// Interface combining properties from Shape and Circle
interface ColoredCircle extends Shape, Circle {
    // No need to redefine properties from Shape and Circle
    // They are inherited automatically
}

Now, we can use the properties and methods of both interfaces in the objects of type ColoredCircle.

const coloredCircle: ColoredCircle = {
  color: 'red',
  radius: 5,
  area() {
      return Math.PI * this.radius ** 2;
  }
};

console.log(coloredCircle.area()); // Output: 78.53981633974483
console.log(coloredCircle.color); // Output: red
console.log(coloredCircle.radius); // Output: 5

4. Interface Merging

Interface merging means if two interfaces are declared in the same scope with the same name, they will join into one bigger interface under that same name with all declared fields.

Consider the following two declarations in Circle interface:

interface Circle {
  radius: number;
}

interface Circle {
  area(): number;
}

It is equivalent to a one definition of Circle interface combining properties and methods of both interfaces:

interface Circle {
  radius: number;
  area(): number;
}

However note that there should be a conflict of member types if two interfaces declare the same field. The member types must match to run the program successfully.

5. Intersection Types

In TypeScript, intersection types allow us to combine multiple types into a single type that has all the features of each individual type. We denote an intersection type using the '&' operator.

interface Color {
  color: string;
}

interface Circle {
  radius: number;
  area(): number;
}

type ColoredCircle = Color & Circle;

We can create objects of ColoredCircle similar to normal interfaces:

const coloredCircle: ColoredCircle = {
  color: 'red',
  radius: 5,
  area() {
      return Math.PI * this.radius ** 2;
  }
};

It is worth noting that at a high level, intersection types and extending multiple interfaces are the same thing. The only big difference is that the interface extension allows us to override and add new properties and methods.

6. Conclusion

This typescript tutorial discussed how to create derived interfaces by extending a single interface or multiple interfaces. We also discussed how we can extend interfaces using the interface merging and intersection types, with examples.

Happy Learning !!

Comments

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.