typeScript 装饰器

137 阅读3分钟

我正在参加「掘金·启航计划」

1. 概念

  • 装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或参数上;
  • 装饰器使用@expression这种形式,expression求值后必须为一个函数,它会在运行时被调用;
  • 装饰器本质上就是一个函数;
  • 装饰器是一项实验性特性,在未来的版本中可能会发生改变;

2. 不同的装饰器

2.1 类的装饰器

类装饰器声明在类声明之前。类装饰器应用于类的构造函数,可用于观察、修改或替换类定义。类装饰器不能在声明文件中使用,也不能在任何其他环境上下文中使用(例如在声明类上)。

类装饰器的表达式将在运行时作为函数调用,被装饰类的构造函数作为唯一参数。

// 类的装饰器
// 装饰器本身就是一个函数
// 类装饰器接收的是一个构造函数
// 装饰器通过 @ 符号来使用
// 类定义的时候去实现

// 写法1
function testDecorator(constructor: any) {
    console.log('decorator')
    constructor.prototype.getName = () => {
        console.log('111')
    }
}

// 写法2
function testDecorator1() {
    return function (constructor: any) {
        console.log('decorator')
        constructor.prototype.getName = () => {
            console.log('111')
        }
    }
}

// 写法3
function testDecorator2(flag: boolean) {
    if(flag) {
        return function (constructor: any) {
            console.log('decorator')
            constructor.prototype.getName = () => {
                console.log('111')
            }
        }
    } else {
        return function (constructor: any) {}
    }
}

// @testDecorator
// @testDecorator1()
@testDecorator2(false)

class Test {}

const test = new Test();
(<any>test).getName()

优化:

// 写法1 还是不能够提示
function simpleDecorator<T extends new (...args: any[]) => any>(constructor: T) {
    return class extends constructor {
        name = 'lee'
        getName() {
            console.log(this.name)
        }
    }
}

// @simpleDecorator
// class Test1 {
//     name: string
//     constructor(name: string) {
//         this.name = name
//     }
// }

// const test1 = new Test1('dell');
// (<any>test1).getName()
// console.log(test1.name)


// 写法2
function simpleDecorator1() {
    return function<T extends new (...args: any[]) => any>(constructor: T) {
        return class extends constructor {
            name = 'lee'
            getName() {
                console.log(this.name)
            }
        }
    }
}

const Test2 = simpleDecorator1()(class {
    name: string
    constructor(name: string) {
        this.name = name
    }
})

const test2 = new Test2('dell');
test2.getName()

2.2 方法装饰器

方法装饰器声明在方法声明之前。该装饰器应用于方法的属性描述符,可用于观察、修改或替换方法定义。方法装饰器不能在声明文件、重载或任何其他环境上下文中使用(例如在声明类中)。

// 在类定义的时候 方法就开始装饰
// 普通方法,target 对应的是类的prototype
// 静态方法,target 对应的是类的构造函数

// 写法1
function getNameDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
    console.log(target, key, descriptor)
    
}
// 写法2
function getNameDecorator1() {
    return function(target: any, key: string, descriptor: PropertyDescriptor) {}
}

class methodTest {
    name: string
    constructor(name: string) {
        this.name = name
    }
    @getNameDecorator
    getName() {
        return this.name
    }
}

const methTest = new methodTest('huihui')
console.log(methTest.getName())

2.3 属性装饰器

在属性声明之前声明属性装饰器。属性装饰器不能在声明文件中使用,也不能在任何其他环境上下文中使用(例如在声明类中)。

// target 指向类的prototype
// 可以使用属性装饰器返回
function nameDecorator(target: any, key: string): any {
    const descriptor: PropertyDescriptor = {
        writable: false
    }
    return descriptor
}

// name 放在实例上
class keyDecorator {
    @nameDecorator
    name = 'huihui'
}

const keyName = new keyDecorator()
keyName.name = 'dell'

2.4 访问器装饰器

访问器装饰器声明在访问器声明之前。访问器装饰器应用于访问器的属性描述符,可用于观察、修改或替换访问器的定义。访问器装饰器不能在声明文件中使用,也不能在任何其他环境上下文中使用(例如在声明类中)。

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

class getDecorator {
    private _name: string
    constructor(name: string) {
        this._name = name
    }
    get name() {
        return this._name
    }
    @visitDecorator
    set name(newName) {
        this._name = newName
    }
}

2.5 参数装饰器

在参数声明之前声明一个参数装饰器。参数装饰器应用于函数,用于类构造函数或方法声明。参数装饰器不能在声明文件、重载或任何其他环境上下文中使用(例如在声明类中)。

// 原型,方法名,参数所在位置索引
function paramDecoratorF(target: any, key: string, paramIndex: number): any {
    console.log(target, key, paramIndex)
}

// name 放在实例上
class paramDecorator {
   getInfo(@paramDecoratorF name: string, age: number) {
    console.log(name, age)
   }
}

const param = new paramDecorator()
param.getInfo('huihui', 12)