How to Extend an Interface With Nested Properties in TypeScript

David Mbochi Njonge Feb 02, 2024
  1. Extend an Interface With Nested Properties Using TypeScript Intersection
  2. Extend an Interface With Nested Properties Using a Separate Interface Structure
  3. Extend an Interface With Nested Properties by Making the Product Interface Generic
How to Extend an Interface With Nested Properties in TypeScript

When we are developing applications, we may get a new requirement that uses the existing structure but with the addition of new properties. Modifying the existing structure might affect other modules of our application, and creating a new structure might lead to redundancy in our code.

In this tutorial, you will learn the different methods that you can use to add new properties to your base structure without modifying it to accommodate your new requirement.

To successfully execute the examples provided in this example, ensure that you have installed TypeScript and Node Package Manager (npm) on your machine.

Extend an Interface With Nested Properties Using TypeScript Intersection

In Set theory, an intersection is a set of elements formed by getting the elements that are common in two sets. An intersection in TypeScript works the same way by returning a new structure made from the common properties of the intersected structures.

To demonstrate this example, open Visual Studio Code editor and create a using-intersection folder.

Inside this folder, create a file named Product.ts. Copy and paste the following code into the file.

export interface Product{
    productName: string
    productPrice: number
    productAddress:{
        houseNumber: number,
        streetName: string
    }
}

The Product.ts file contains an interface named Product, and inside this interface, we have defined a structure named productAddress. In the next step, we will add a new property to the structure without modifying the above code.

In the same folder, create a file named NewProduct.ts. Copy and paste the following code into the file.

import { Product } from "./Product";

export type NewProduct = Product &{
    productAddress:{
        zipCode: string
    }
}

let productInfo: NewProduct = {
    productName: "Nike - Air Max",
    productPrice: 500,
    productAddress:{
        houseNumber: 1233,
        streetName: "brooklyn street",
        zipCode: "1233"
    }
}

console.log(productInfo.productName)
console.log(productInfo.productPrice)
console.log(productInfo.productAddress)

The NewProduct.ts file defines a new interface type named NewProduct using the type keyword. The NewProduct type is intersected with the Product interface using the & symbol and adds a new property named zipCode to the base structure productAddress.

The productInfo object contains an instance of NewProduct. Note that the new structure has all the properties in the base structure and the property of the intersected structure.

Go to your terminal and cd to the folder’s location to run this code. Use the following command to generate a tsconfig.json file for our configuration.

david@david-HP-ProBook-6470b:~/Documents/using-intersection$ tsc --init

Ensure you have the following configuration properties in the tsconfig.json file generated on your package.

{
    "compilerOptions":{
        "target": "es5"
        "noEmitOnError":true,
    }
}

Use the following command to transpile all your TypeScript files to Java files.

david@david-HP-ProBook-6470b:~/Documents/using-intersection$ tsc

Use the following command to run the example above.

david@david-HP-ProBook-6470b:~/Documents/using-intersection$ node NewProduct.js

Output:

Nike - Air Max
500
{ houseNumber: 1233, streetName: 'brooklyn street', zipCode: '1233' }

Extend an Interface With Nested Properties Using a Separate Interface Structure

Creating a new interface with its properties and extending the base interface is the second way to add properties to the base structure without modifying it.

Create a folder named separate-interface, and create a file named ProductAddressStructure.ts inside the folder. Copy and paste the following code into the file.

export interface ProductAddressStructure{
    houseNumber: number
    streetName: string
}

The code above defines our base structure that we want to add properties without modifying. Create a file named Product.ts under the same folder. Copy and paste the following code into the file.

import { ProductAddressStructure } from "./ProductAddressStructure"

export interface Product{
    productName: string
    productPrice: number
    productAddress: ProductAddressStructure
}

The code above defines a Product interface that adds the properties productName and productPrice. If we want to add a new property to the base structure without modifying it, we have to create a new interface containing the new property and extend the base structure.

Create a file named NewProductAddressStructure.ts under the same folder. Copy and paste the following code into the file.

import { ProductAddressStructure } from "./ProductAddressStructure";

export interface NewProductAddressStructure extends ProductAddressStructure{
    zipCode: string
}

The above code creates a new interface containing the property zipCode and inherits all the properties from the base structure ProductAddressStructure.

Create a file named NewProduct.ts inside the same folder. Copy and paste the following code into the file.

import { NewProductAddressStructure } from "./NewProductAddressStructure";
import { Product } from "./Product";

export interface NewProduct extends Product{
    productAddress: NewProductAddressStructure
}

let productInfo: NewProduct ={
    productName: "Nike - Air Max",
    productPrice: 500,
    productAddress: {
        zipCode: "1233",
        houseNumber: 345,
        streetName: "brooklyn street"
    }
}

console.log(productInfo.productName)
console.log(productInfo.productPrice)
console.log(productInfo.productAddress)

The NewProduct.ts file defines an interface named NewProduct that inherits the productName and productPrice from the ProductPrice. The NewProduct interface also implements the NewAddressStructureInterface composed of the properties in the new structure and the inherited structure.

Use the same steps we used to execute the first example to run this example.

Output:

Nike - Air Max
500
{ zipCode: '1233', houseNumber: 345, streetName: 'brooklyn street' }

Extend an Interface With Nested Properties by Making the Product Interface Generic

This approach is similar to the one we have above, except that the Product interface is generic.

Create a folder named generic-interface, and create a file named ProductAddressStructure.ts. Copy and paste the following code into the file.

export interface ProductAddressStructure{
    houseNumber: number
    streetName: string
}

The above interface creates the base structure containing two properties.

Create a file named Product.ts inside the same folder. Copy and paste the following code into the file.

import { ProductAddressStructure } from "./ProductAddressStructure"

export interface Product<T extends ProductAddressStructure> {
    productName: string
    productPrice: number
    productAddress: T
}

The Product.ts file defines a generic interface named Product. The interface will restrict the implementation to structures that only inherit from the ProductAddressStrcture.

The interface also contains a field named productAddress that will be resolved to a type of the ProductAddressStructure instance.

Create a file named NewProductAddressStructure.ts in the same folder. Copy and paste the following code to the file.

import { ProductAddressStructure } from "./ProductAddressStructure";

export interface NewProductAddressStructure extends ProductAddressStructure{
    zipCode: string
}

The NewProductAddressStructure.ts defines a new interface named NewProductAddressStructure that inherits all the base properties of the ProductAddressStructure interface.

Create a file named NewProduct.ts under the same folder. Copy and paste the following code into the file.

import { NewProductAddressStructure } from "./NewProductAddressStructure";
import { Product } from "./Product";

export interface NewProduct extends Product<NewProductAddressStructure>{

}

let productInfo: NewProduct = {
    productName: "Nike - Air Max",
    productPrice: 500,
    productAddress: {
        zipCode: "1233",
        houseNumber: 1233,
        streetName: "brooklyn street"

    }
}

console.log(productInfo.productName)
console.log(productInfo.productPrice)
console.log(productInfo.productAddress)

The NewProduct.ts file defines an interface named NewProduct. The NewProduct interface inherits all the properties from the Product, including the generic structure productAddress that contains the property zipCode from the NewProductAddressStructure interface.

Since the NewProductAddressStructure inherits from the base structure ProductAddressStructure, the NewProduct interface also contains the properties houseNumber and streetName.

Use the steps we used to execute the first step to run this example.

Output:

Nike - Air Max
500
{ zipCode: '1233', houseNumber: 1233, streetName: 'brooklyn street' }
David Mbochi Njonge avatar David Mbochi Njonge avatar

David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.

LinkedIn GitHub

Related Article - TypeScript Interface