HomeAboutRelease Notes

Study Note with Decorator In TypeScript (2) - Method Decorator

June 03, 2019

Inroduction

Last week I have introduced simple property decorator. This week, I would like to talk about method decorators and provide a simple example to help understanding.

Definition of Method Decorator

According to the definition from TypeScript documentation

A Method Decorator is declared just before a method declaration. The decorator is applied to the Property Descriptor for the method, and can be used to observe, modify, or replace a method definition. A method decorator cannot be used in a declaration file, on an overload, or in any other ambient context (such as in a declare class).

In my understanding, a method decorator is just a function which takes the decorated function, its name and properties as parameters and then process the target by adding your own logics.

Simple Example

Step 1: Know what parameters are needed for a method decorator

Let’s see a simple example of method decorator

class MyClass { public message: String = "I am called"; @MyMethodDecorator public myMethod() { console.log(this.message); } } function MyMethodDecorator( target: any, propertyKey: string, descriptor: PropertyDescriptor ) { console.log("target: ", target); console.log("propertyKey: ", propertyKey); console.log("descriptor: ", descriptor); } const myClass = new MyClass(); myClass.myMethod();

The output is printed as shown below:

target: MyClass { myMethod: [Function] } propertyKey: myMethod descriptor: { value: [Function], writable: true, enumerable: true, configurable: true } I am called

As shown, the 3 parameters required for method decorator are target: the class itself , propertyKey: the name of the method and descriptor: the meta-data to describe this method, e.g. writable, enumerable or configurable. Interestingly, if you are aware of Object.defineProperty(obj, prop, descriptor) function, you would notice that the 3rd parameter of this function also accepts a data strcture called descriptor.

Step 2: Let’s implement something in the method decorator

Take writable as an example. This property defines whether the target is allowed to be written. If it’s set to false, you can never change the value of the target anymore.

For example, let’s change the MyMethodDecorator() as shown below

function MyMethodDecorator( target: any, propertyKey: string, descriptor: PropertyDescriptor ) { descriptor.writable = false; }

At the end of the program, change the last 2 lines of codes to the codes below.

const myClass = new MyClass(); myClass.myMethod(); myClass.myMethod = function() { console.log("I am changed"); }; myClass.myMethod();

After we call myMethod(), which will print “I am called”, we then assign the myMethod to point to another function, which will print "I am changed". Then we call the method again. You may probably think, at the second time, it will print "I am changed".

However, the actual output of the program is

I am called I am called

It is because we have set the descriptor.writable to false. From this example, we can know how modifying the descriptor in a decorator would affect the method.

Step 3: Remove the decorator and see how it goes

Now let’s remove the @MyMethodDecorator from the myMethod method and run the program again.

class MyClass { public message: String = "I am called"; //@MyMethodDecorator public myMethod() { console.log(this.message); } }

Now the program should print 2 different lines of words as below

I am called I am changed

Conclusion

This article briefly introduces how it actually works with a method decorator. I try to use the simplest example to explain a basic usage of it. In real life, we can actually utilise this feature to do many creative works. If you are interested, you may read through the source code of MobX because it frequently uses decorators. Once of a commonly used method decorator in MobX is computed, you may read the MobX source code here to see how a method decorator creates magic!

Related


Written by Yi Zhiyue
A Software Engineer · 山不在高,有仙则灵
LinkedIn · GitHub · Email