How to Use Extension Methods in TypeScript?


As a TypeScript developer, you may encounter situations where you need to add functionality to an existing class or interface without modifying its source code. In such cases, extension methods can come in handy. Extension methods allow you to add new methods to a class or interface, providing additional functionality to make your code more modular and easier to maintain.

In this tutorial, we will see what extension methods are, how to declare and use them and provide examples of their use.

What are Extension Methods?

Extension methods are a powerful feature of TypeScript that allows you to add new functionality to existing classes or interfaces without modifying their source code. They are declared as standalone functions but can be called as if they were methods of the extended class or interface.

To declare an extension method, you must define a new function that accepts an instance of the class or interface you want to extend as its first parameter. The ‘this’ keyword is used to specify the type of the object that the function is being called on.

Syntax

The syntax for declaring an extension method is as follows −

declare global {
   interface <ClassOrInterface> {
      <methodName>(...args): <returnType>;
   }
}
<ClassOrInterface>.prototype.<methodName> = function(...args): <returnType> {
   // implementation
}

Here, <ClassOrInterface> represents the name of the class or interface you want to extend, <methodName> represents the name of the new method, and <returnType> represents the return type of the method.

Example 1

Let's look at an example of how to declare an extension method for the Array class. Once you have declared an extension method, you can use it just like any other class or interface method. Here is an example of how to use the sum method that we declared in the previous section −

interface Array<T> {
   sum(): number;
}
Array.prototype.sum = function(): number {
   return this.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
}
const numbers = [1, 2, 3, 4, 5];
const total = numbers.sum();
console.log(total);

On compiling, it will generate the following JavaScript code −

Array.prototype.sum = function () {
   return this.reduce(function (accumulator, currentValue) { return accumulator + currentValue; }, 0);
};
var numbers = [1, 2, 3, 4, 5];
var total = numbers.sum();
console.log(total);

Output

The above code will produce the following output −

15

In this example, we call the sum method on an array of numbers. The result is the sum of all the elements in the array.

Example 2

Another example of an extension method is one that capitalizes the first letter of a string. Here is how you can declare and use this extension method−

interface String {
   capitalize(): string;
}
String.prototype.capitalize = function(): string {
   return this.charAt(0).toUpperCase() + this.slice(1);
}
const myString = "hello world";
const capitalizedString = myString.capitalize();
console.log(capitalizedString);

On compiling, it will generate the following JavaScript code −

String.prototype.capitalize = function () {
   return this.charAt(0).toUpperCase() + this.slice(1);
};
var myString = "hello world";
var capitalizedString = myString.capitalize();
console.log(capitalizedString);

Output

The above code will produce the following output −

Hello world

In this example, we declare a new method called capitalize for the String class. The capitalization method takes the first letter of a string and capitalizes it. We then use the capitalize method on a string variable called myString, resulting in a new string with the first letter capitalized.

Example 3

Let’s look at another example of an extension method that converts a string into a title case. It capitalizes the first character of every word in the string.

class StringOperations {
   static toTitleCase(str: string): string {
      return str.replace(
         /\w\S*/g,
         (txt: string) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
      );
   }
}
interface String {
   toTitleCase(): string;
}
String.prototype.toTitleCase = function (): string {
   return StringOperations.toTitleCase(this);
};

const title: string = "the quick brown fox jumps over the lazy dog";
console.log(title.toTitleCase()); // The Quick Brown Fox Jumps Over The Lazy Dog

On compiling, it will generate the following JavaScript code −

var StringOperations = /** @class */ (function () {
   function StringOperations() {
   }
   StringOperations.toTitleCase = function (str) {
      return str.replace(/\w\S*/g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); });
   };
   return StringOperations;
}());
String.prototype.toTitleCase = function () {
   return StringOperations.toTitleCase(this);
};
var title = "the quick brown fox jumps over the lazy dog";
console.log(title.toTitleCase()); // The Quick Brown Fox Jumps Over The Lazy Dog

Output

The above code will produce the following output −

The Quick Brown Fox Jumps Over The Lazy Dog

In this example, we first declare a StringOperations class that contains a static method called toTitleCase(). This method takes a string parameter and returns the title case of the string. The implementation of the toTitleCase() method uses a regular expression to match all word characters in the string and applies the toUpperCase() and toLowerCase() methods to the appropriate characters.

Next, we declare a global interface String that extends the built-in String interface with a new method signature called toTitleCase(). It returns a string. Finally, we use prototype augmentation to add the toTitleCase() method to the String prototype.

As you can see, the toTitleCase() method is now available on all string instances, allowing us to easily convert a string to a title case without writing the implementation ourselves whenever needed.

Conclusion

In conclusion, extension methods in TypeScript provide a way to add functionality to existing classes and interfaces without modifying their original definitions. This is particularly useful when working with built-in classes and interfaces such as Array and String. We can easily add new methods to these classes and interfaces by using extension methods, improving their usability, and reducing code duplication.

When using extension methods, it is important to follow best practices, such as properly encapsulating the implementation of the method and avoiding clashes with existing methods or properties. With the right approach, extension methods can greatly enhance the functionality and usability of your TypeScript code.

Updated on: 31-Aug-2023

6K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements