Original address: netbasal.com/create-and-…

I remember the first time I saw this sexy symbol. Yes, you know what I’m talking about. The at sign (@), Above or before class, property ora method — a Decorator. I remember the first time I saw this sex symbol, and yes, you know what I’m talking about. The symbol (@) before or after a class, property, or method — decorator.

Decorators are a mechanism for observing, modifying, or replacing classes, methods or properties in a declarative fashion. Decorators are a mechanism for viewing, modifying, or replacing types, methods, or properties declaratively.

Decorators are a proposed standard in ECMAScript2016. In Typescript, We can enable them by setting the “experimentalDecorators” compiler flag, or with babel by installing the babel-plugin-transform-decorators plugin. Decorators are a proposed standard in ECMAScript2016. In Typescript, we can start them by setting the “experimentalDecorators” editor flag, or by installing the babel-plugin-transform-decorators plug-in with Babel.

Creating decorators is actually quite easy. Let’s explore the various decorators. Creating decorators is really easy. Let’s start exploring the various decorators.

Class Decorators Class Decorators

A Class decorator is a function that takes the constructor of the class as the only parameter. If the class decorator returns a value, it will replace the class declaration with the provided constructor function, i.e., Override the constructive. Class decorator is a function that takes the Class’s constructor as its only argument. If the Class decorator returns a value, it replaces the Class declaration with the provided constructor, that is, overriding the constructor.

Let’s see an example of how to override the constructor. Look at an example of overriding a constructor

function clean(constructor) {
  return class extends constructor {
    ngOnDestroy() {
      console.log('Cleaning.... ')
      // Auto Clean things and call the original method
      constructor.prototype.ngOnDestroy.apply(this.arguments);
    }
  }
}

@clean
class HelloComponent {
  ngOnDestroy() {
    console.log('ngOnDestroy - HelloComponent'); }}const helloComponet = new HelloComponent();
helloComponet.ngOnDestroy();
Copy the code

Compiled code:

var _class;

function clean(constructor) {
  return class extends constructor {
    ngOnDestroy() {
      console.log('Cleaning.... '); // Auto Clean things and call the original method

      constructor.prototype.ngOnDestroy.apply(this.arguments); }}; }let HelloComponent = clean(_class = class HelloComponent {
  ngOnDestroy() {
    console.log('ngOnDestroy - HelloComponent');
  }

}) || _class;

const helloComponet = new HelloComponent();
helloComponet.ngOnDestroy();
Copy the code

We are returning a brand new Class that extends the original constructor function, in our case, the HelloComponent. We return a brand new class that inherits the original constructor, in our case, HelloComponent.

Let’s see an example of how to greet the existing constructor. Let’s say we work with React and we want to know when React calls the render method. Let’s look at an example of how to decorate an existing constructor. Suppose we use React, we want to know when React calls the Render method.

function logRender(constructor) {
  const original = constructor.prototype.render;

  constructor.prototype.render = function() {console.log(`Rendering ${constructor.name}. `);
    return original.apply(this.arguments);
  }
}

@logRender
class Todos extends Component {
  render() {
    return null}}Copy the code

We start by saving a reference to the original method, create a new one, call what we need and return the original method, letting React do its magic. We first save the reference to the original method, then create a new crime method, perform what we need and return to the original method to make React work magic.

You can find a real-life example in this repository. You can find some real examples in this warehouse.

Method Decorators (Method Decorators)

A Method decorator is A function that takes three parameters.

The target:

Either the constructor function of the class for a static member, or the prototype of the class for an instance member. The constructor of a class for a static member, or the prototype of a class for an instance member.

The key: The method name.

The descriptor: The Property Descriptor for the method. Method property description.

Let’s see an example of how to decorate an existing method with the setTimeout API. But before we can proceed, if you remember, the setTimeout function takes a number of milliseconds to wait before executing the code, so we need to learn how to pass options to a decorator by using a Decorator Factory. Let’s look at an example of how setTimeout can be used to decorate an existing method. But before we continue, if you remember, the setTimeout method waits a few milliseconds before executing, so we need to learn how to use the decorator factory to pass parameters to the decorator.

A Decorator Factory is simply a function that returns the expression that will be called by the decorator at runtime. The decorator factory is just a function that returns the expression that the decorator calls at run time.

Or in plain English, function that returns function. In plain English, a function that returns a function.

function clean(constructor) {
  return class extends constructor {
    ngOnDestroy() {
      console.log('Cleaning.... ')
      // Auto Clean things and call the original method
      constructor.prototype.ngOnDestroy.apply(this.arguments); }}}function timeout(milliseconds = 0) {
  return function(target, propertyKey, descriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function() {
      setTimeout(() = > {
        originalMethod.apply(this.arguments);
      }, milliseconds)
    };

    return descriptor;
  }
}

@clean
class HelloComponent {
  ngOnDestroy() {
    console.log('ngOnDestroy - HelloComponent');
  }

  @timeout() 
  demoMethod() {
    console.log('demoMethod');
  }
  
  @timeout(2000)
  demoMethod2() {
    console.log('demoMethod2'); }}const helloComponet = new HelloComponent();
helloComponet.ngOnDestroy();
helloComponet.demoMethod();
helloComponet.demoMethod2();
Copy the code

We can get a reference to the original method from the descriptor value property. Then, we will override the original value and create a new function that wraps the original with setTimeout. We can get a reference to the original method from the value property of descriptor. Then, we’ll override the original value and create a new function wrapped in setTimeout.

Remember that you can also use a method decorator with static methods, for example:

class Test {
    
    @log
    static someMethod(){}}Copy the code

The only difference in this case is you will get the constructor function of the class and not the prototype of the class. In this case, the only difference is that you get the constructor of the class instead of a similar prototype.

You can find a real-life examples in this repository. You can find some examples in this warehouse.

Property Decorators

A Property Decorator is declared just before a property declaration. Same as the others, It’s a function that takes two parameters. Property decorators are declared before properties are declared. Like any other function, it is a function with two arguments.

The target:

Either the constructor function of the class for a static member, or the prototype of the class for an instance member. Either a class constructor for a static member or a class prototype for an instance member.

The key:

The property name

Let’s see an example of how to decorate a property. Look at an example of how to decorate properties.

/** * Attribute decorator */

function logProperty(target, key) {
  let value;
  const getter = function() {
    console.log(`Get => ${key}`);
    return value;
  }

  const setter = function(newVal) {
    console.log(`Set: ${key}= >${newVal}`);
    value = newVal;
  }

  Object.defineProperty(target, key, {
    get: getter,
    set: setter,
    enumerable: true.configurable: true})}Copy the code

The logProperty decorator above redefines the decorated property on the object. We can define a new property to the Constructor’s prototype by using the object.defineProperty () method.here, We’re using get to return the value and log it. Secondly, We’re using set to directly write a value to the internal property and log it. The above logProperty decorator redefines the properties on the object. We can define a new property on the constructor prototype using the object.defineProperty () method. Here, we use the get return value and record it. Second, we use set to write a value directly to the internal property and log it.

We can also use the new Reflect API instead of the defineProperty() method. We can also use the new Reflect API instead of the defineProperty() method.

Reflect.deleteProperty[key];
Reflect.defineProperty(target, key, {
    get: getter,
    set: setter,
})
Copy the code

Now we can use our decorator like this:

class Person { 
	
  @logProperty
  public name: string;

  constructor(name : string) { 
    this.name = name; }}let p = new Person("netanel");
p.name = "Netanel";
const name = p.name;

// Set: name => netanel
// Set: name => Netanel
// Get => name
Copy the code

You can find a real-life example in this repository. You can find some real examples in this warehouse.

Parameter Decorators

I’m going to skip this explanation because it’s the least common and it usually comes in conjunction with a method decorator. You can find a detailed example in the official documentation. I’ll skip this section because it’s not very common, and it’s often used in conjunction with method decorators, a detailed example of which can be found in the official documentation.

Composing Decorators

When multiple decorators apply to a single declaration, their evaluation is similar to function composition in mathematics. For example, the following code: When multiple decorators are applied to a single declaration, their calculation is analogous to a combination of functions in mathematics, of the following type:

class TodosService {

  @decoratorTwo
  @decoratorOne
  someMethod(){}}Copy the code

is equivalent to decoratorTwo(decoratorOne(someMethod)). Equivalent to decoratorTwo(decoratorOne(someMethod)).

Testing Decorators

I’m going to use jest for testing, but you can use whatever test library you like. We have two ways to test decorators. I’ll use Jest as a test, but you can use any library you like. There are two ways to test decorators.

  1. Use them in your tests like in your code.
  2. Use it in tests, just like in code.
describe('@logRender Decorator'.() = > {

  @logRender
  class Todos {
    render() {
      return. } } it('should call console.log'.() = > {
     const spy = jest.spyOn(console.'log');
     const todos = new Todos().render();
     expect(spy).toBeCalledWith('Rendering Todos... ');
  });

});
Copy the code
  1. Since decorators are just functions we can test them like any other function.
  2. Since decorators are just functions, we can test them just like any other function.
describe('@logRender Decorator'.() = > {

  class Todos {
    render() {
      return. } } it('should call console.log'.() = > {
    const spy = jest.spyOn(console.'log');
    logRender(Todos);
    const todos = new Todos().render();
    expect(spy).toBeCalledWith('Rendering Todos... ');
  });

});
Copy the code

Let’s close the article by testing the @timeout decorator. Let’s close by testing the @timeout decorator.

jest.useFakeTimers();

class Test {
  method() {
    console.log('Worked');
  }
}

describe('@timeout'.function () {

  it('should call setTimeout'.function () {
    timeout(1000)(Test.prototype, 'method'.Object.getOwnPropertyDescriptor(Test.prototype, 'method'));
    new Test().method();
    expect(setTimeout['mock'].calls.length).toBe(1);
    expect(setTimeout['mock'].calls[0] [1]).toBe(1000);
  });
  
});
Copy the code

We are passing the necessary parameters manually to the timeout decorator and leveraging the useFakeTimers feature from jest to check if our setTimeout function was called. We will manually pass the necessary parameters to the timeout decorator and use the useFakeTimers feature in Jest to check if the setTimeout function is called.

Wrapping Up this book

You can leverage decorators in your apps and create powerful things with them. Decorators are not only for frameworks or libraries, they are worth the time to learn as they can make your code more extensible and even more readable. Decorators also Promote code reuse. Give them a try sometime soon 🙏 You can use decorators in your references to create great things. Decorators aren’t just used in frameworks and libraries; they are well worth learning because decorators can make your code more extensible and readable. Decorators also promote code reuse. Try it soon