TypeScript learning Chapter 10 - decorator

A decorator is a special type of declaration that can be attached to a class declaration, method, property, or parameter to modify the behavior of the class. Generally speaking, decorator is a method, which can be injected into classes, methods and attribute parameters to expand their functions. There are two ways to write a decorator: ordinary decorator (unable to pass parameters) and decorator factory (able to pass parameters). Common decorators include: class decorator, attribute decorator, method decorator and parameter decorator.

Class 1 decorator

// Decorator
function logClass(params:any){
    
    // params is the current HttpClient class

    // Extending properties to classes through decorators
    params.prototype.url="www.baidu.com";

    // Extending methods to classes through decorators
    params.prototype.run = function(){
        console.log('this is run function');
    }
}

@logClass
class HttpClient{
    constructor(){

    }
    getData(){

    }
}
var http = new HttpClient();

console.log(http.url);
// www.baidu.com

http.run();
// this is run function'

Decorator can pass parameters, commonly known as decorator factory.

// Decorator
function logClass(params:any){
    return function(target:any){
        // target is the current HttpClient class

        // Extending properties to classes through decorators
        target.prototype.url = params;
        // Extending methods to classes through decorators
        target.prototype.run = function(){
            console.log(this.url);
        };
    }
}

@logClass('www.baidu.com')
class HttpClient{
    constructor(){

    }
    getData(){

    }
}

var http = new HttpClient();
console.log(http.url);
// www.baidu.com

http.run();
// www.baidu.com

Class decorators can also overload constructors.

function logClass(target:any){
    // tartget is the current HttpClient class
    return class extends target{
        // Overloading properties and methods in constructors
        url:any = 'I'm in the decorator url';
        getData(){
            this.url = 'I was modified in the decorator url';
            console.log(this.url);
        }
    }
}

@logClass
class HttpClient{
    public url:string | undefined;
    constructor(){
        this.url = 'I'm in the constructor url'
    }
    getData(){
        console.log(this.url);
    }
}

var http = new HttpClient();
http.getData();
// I am the modified url in the decorator

2. Attribute decorator

The property decorator takes two parameters, the first is the constructor or prototype object of the class, and the second is the parameter of the current decoration.

// Attribute decorator
function logPrototype(params:string){
    return function(target:any,attr:any){
        // target is the constructor of the class if it is a static member
        // target is the prototype object of the class if it is an instance member
        // attr is the current parameter
        target[attr]=params;
    }
}
class HttpClient{
    @logPrototype('www.qq.com')
    public url:string | undefined;
    constructor(){
        
    }
    getData(){
       console.log(this.url);
    }
}

var http = new HttpClient();
http.getData();
// www.qq.com

3. Method decorator

The property decorator takes three parameters, the first is the constructor or prototype object of the class, the second is the name of the member, and the third is the property description of the member.

// Method decorator
function logMethod(params:any){
    return function(target:any,methodName:any,desc:any){
        // target is the constructor of the class if it is a static member
        // target is the prototype object of the class if it is an instance member
        // methodName is the current method
        // desc is the description of the method, including configuration, enumeration, writable and other information

        // Extending class properties and methods in decoration
        target.apiUrl = 'www.qq.com';
        target.run = function(){
            console.log('this is run function');
        }

    }
}

class HttpClient{
    public url:string | undefined;
    constructor(){}
    @logMethod('www.baidu.com')
    getData(){

    }
}

var http = new HttpClient();
// console.log(http.apiUrl);
// www.qq.com

// http.run();
// this is run function

Modifying methods with decorators

// Method decorator
function logMethod(params:any){
    return function(target:any,methodName:any,desc:any){
        // target is the constructor of the class if it is a static member
        // target is the prototype object of the class if it is an instance member
        // methodName is the current method
        // desc is the description of the method, including configuration, enumeration, writable and other information

        // How to modify a decorator
        // Change all the parameters passed in the decorator method to string type

        // 1. Method before saving
        var oldMethod = desc.value;
        // 2. Operation data
        desc.value = function(...args:any[]){
            args = args.map((value)=>{
                return String(value);
            })
            // 3. The object pretends to inherit
            oldMethod.apply(this,args);
        }
    }
}

class HttpClient{
    public url:string | undefined;
    constructor(){}
    @logMethod('www.baidu.com')
    getData(...args:any[]){
        console.log(args);
        console.log('this is getData function')
    }
}

var http = new HttpClient();

http.getData(1000,2000);
// [ '1000', '2000' ]
// this is getData function

4. Method parameter decorator

The parameter decorator expression will be called as a function at runtime. You can use the parameter decorator to add some element data to the prototype of the class and receive three parameters. The first is the constructor or prototype object of the class, the second is the name of the method, and the third is the index of the parameter in the function parameter list.

function logParams(params:any){
    return function(target:any,methodName:any,paramsIndex:any){
        console.log(params); 
        // username 
        console.log(target); 
        // HttpClient { getData: [Function] }
        console.log(methodName); 
        // getData
        console.log(paramsIndex); 
        // 0

        // Extend properties to the current class through the property decorator
        target.currentUser = params;

    }
}
class HttpClient{
    public url:string | undefined;
    constructor(){}
    getData(@logParams('username') username:any){
        console.log(username);     
        // aiguangyuan
    }
}
var http = new HttpClient();
http.getData('aiguangyuan');
console.log(http.currentUser);
// username

 

242 original articles published, 200 praised, 30000 visited+
Private letter follow

Tags: Attribute

Posted on Sat, 11 Jan 2020 23:00:17 -0800 by gterre