// Tutorial //

Module Augmentation in TypeScript

Published on September 5, 2019
Default avatar
By Alfred M. Adjei
Developer and author at DigitalOcean.
Module Augmentation in TypeScript

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Before getting into module augmentation, let’s look at some TypeScript merging principles which will become useful as we progress.

In this post we talked about merging interfaces with interfaces. Additionally, we can merge interfaces with classes too. Let’s look at an example.

class Food {
  cheese: string;

interface Food {
  bacon: string;

const food  = new Food();
food.bacon = "nice bacon";
food.cheese = "sweet cheese";

console.log(food); // {bacon: "nice bacon", cheese: "sweet cheese"}

In our example above, we can see that, the food variable contains both bacon and cheese even though only cheese was declared in the Food class. This is because, the interface was merged with the class.

But what if our interface contains a method, for example, bake

class Food {
  cheese: string;

interface Food {
  bacon: string;
  bake(item: string);

const food  = new Food();

food.bake("cake"); // Error: food.bake is not a function

Though, the bake method will be shown on the food variable with the help of intelliSense, because the class Food and the interface Food will be merged, calling the bake method will result in an error because interfaces contain only declaration but not implementations. To solve this, we can add the implementation of bake to the Food prototype.

Food.prototype.bake = (item) => console.log(item);

Now calling the bake method will work.

food.bake("cake"); // cake

Enter Module Augmentation

Module augmentation helps us to extend functionalities to third party libraries we may not have access to or classes in other files.

Say we have a Pet class with a name property and feed method.

export class Pet {
  name: string;

  feed(feedType: string) {

We then decide to import this class into our index.ts file but instead of using only the methods and properties in the Pet class, we want to add more functionalities. We can do that using module augmentation.

First, we import our Pet class into our index.ts file.

import { Pet } from "./pet";

./pet is a module. In order to extend it, we have a declare a module using the same name and in that module, we will declare an interface with the same name as the class we are trying to extend. In the interface, we will include the properties and methods we want to add to the extended class.

declare module "./pet" {
  interface Pet {
    age: number;
    walk(location: string);

TypeScript will merge both the Pet class and the Pet interface because they can be found in the same ./pet module.

But that’s not all. Remember I explained that, interfaces don’t contain implementation for methods but only their declarations. For that reason, we will add the implementation of the walk method to the prototype of Pet.

Pet.prototype.walk = (location:string) => `Likes to walk in the ${location}`

Now we can call both the methods and properties found in the Pet class and the newly declared Pet interface.

const pet = new Pet();

pet.name = "Looty";
pet.age = 3;

pet.feed("bacon"); // bacon
console.log(pet.name = "Looty"); // Looty
console.log(pet.age = 3); // 3
console.log(pet.walk("park")); // Likes to walk in the park

Now you may be wondering, instead of declaring an interface then adding the implementation of walk method to the Pet prototype, why didn’t we just declare a class with the same name so that when the class is initialized, we will have methods from both classes?

The answer is, TypeScript doesn’t allow merging between classes so we can’t create two or more classes with the same name. If you want to merge classes, there is a workaround using TypeScript mixins discussed about in this post or you can use a library I created just for that.

That’s it. Hope this was useful. 😎👌

Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Dear Alfred M. Adjei, Thank you for the great article!

But I have a question about node_modules class.

I want to augment class from node_modules and write like as your code. But tsc say: TS2339: Property ‘age’ does not exist on type ‘TransactionSettings’. Can you help me to augment external class ?

import { Ydb } from ‘ydb-sdk’;

declare module ‘ydb-sdk’ { // eslint-disable-next-line @typescript-eslint/no-namespace namespace Table { interface TransactionSettings { age: number; walk(location: string): void; } } }

// @ts-ignore Ydb.Table.TransactionSettings.prototype.walk = (location: string) => Likes to walk in the ${location};

const a = new Ydb.Table.TransactionSettings({ serializableReadWrite: {} }); console.log(a);