Extension Methods
Extension method allows us to add new methods to types without creating a new instance or modifying the original type. An extension method can be called directly as static methods. Extension method allows your class to extend without having to change your source code or relying on the inheritance.
Let’s take an example. I want to add a static method to Date type. Let’s say new method name is addMilliSec. The first thing we need to do is define the method in date interface. But how can we find the date interface? That’s where lib.d.ts comes in handy.
lib.d.ts
This lib contains the ambient declaration of the javascript construct. This enables us to write the type checked javascript code. For example, everyone knows toString function.
var foo = 123;
var bar = foo.toString();
This code type checks fine because the toString function is defined in lib.d.ts for all JavaScript objects.
If you use the same sample code with the noLib option you get a type check error:
var foo = 123;
var bar = foo.toString(); // ERROR: Property 'toString' does not exist on type 'number'.
Ok, back to extensions. So now if you open the lib.d.ts file you can see a lot of interfaces and ambient declarations (ambient declarations tell to the compiler, what are the available functions/variables by using declare keyword). Since we are adding a new method to Date type, we need to modify the DateConstructor interface. But wait, how can we add our addMilliSec method to this interface. Obviously, we can’t modify the lib.d.ts file. Well, Typescript has a solution for this. If we declare more that one interface with the same name and different properties, At the compile time Typescript, combine all the properties. So no we can extend the DateConstructor interface in the same way as below. (Add this to main.ts file).
interface DateConstructor {
addMilliSec: (milliSec: number) => Date;
};
addMilliSec() is defined in the DateConstructor interface as expected, but you define the method on the Date object:
Date.addMilliSec = function(milliSec: number): Date {
return new Date(this.now() + milliSec);
}
Now in your component, we can call it like this
console.log(Date.addMilliSec(60000)) // Add one minute to current time
Congratulations. You just created an extension method to Date type. None of this is limited to just Date types, you can extend numbers, strings, elements, and even the document native type for additional DOM methods. All you need to do is find the relevant interface from the lib.d.ts file and follow the above procedure.
When not to use the extension methods.
Even though extension methods are very useful, it’s not best practice to use it every time. For example, if you have full control over your class you don't need an extension method. Here's a couple of rules to consider when deciding on whether or not to use extension methods
- Extension methods cannot be used to override existing methods
- An extension method with the same name and signature as an instance method will not be called.
- The concept of extension methods cannot be applied to fields, properties or events
- Use extension methods sparingly….overuse can be a bad thing!
Here is a sample demo to play with. Thanks!!!