TypeScript-进阶(七)-装饰器

118 阅读3分钟

1.装饰器

装饰器是一种特殊的声明,可以附加到类声明、方法、属性或参数上,以修改其行为。装饰器为 TypeScript 提供了一种元编程的方式,使得你可以在编译时对类和类成员进行注解或修改。
在js中,装饰器本质是一个函数(会参与运行) 装饰器可以修饰:

  • 成员(属性+方法)
  • 参数

2.配置

experimentalDecorators 是 TypeScript 中的一个编译选项,用于启用实验性的装饰器特性。

{
  "compilerOptions": {
    "experimentalDecorators": true, // 用于启用实验性的装饰器特性。
  },
}

3.类装饰器

3.1 类装饰器的使用

类装饰器的本质是一个函数,该函数接收一个参数,表示类本身,且类装饰器可以有返回值:

  • void:表示仅运行函数
  • 返回一个新的类:表示新的类替换掉装饰的目标
// 仅运行函数
function test(target: new () => object) {
    
}

@test
class A {
    name: string = '测试'
}


const a: A = new A()
console.log(a.name); // 测试

// 替换装饰目标
function test(target: new () => object) {
    return class B extends target {
        name: string = '这是一个新的类'
    }
}

@test
class A {
    name: string = '测试'
}


const a: A = new A()
console.log(a.name); // 这是一个新的类

3.2 存在多个装饰器

若有多个装饰器时,则会按照装饰器的书写顺序,后加入的先调用


type Target = new () => object

function test2(target: Target) {
    console.log('这是类C');
    return class C {
        name: string = ''
    }
}


function test(target: Target) {
    console.log('这是类B');
    return class B extends target {
        name: string = '这是一个新的类'
    }
}

@test2
@test
class A {
    name: string = '测试'
}
// 这是类B
// 这是类C

3.3 装饰器传递参数

通过函数返回一个装饰器,实现参数传递

type Target = new (...args: any[]) => object

function test(n: string) {
    console.log(n); // 你好啊
    return function (target: Target) {
        return class B extends target {
            name: string = '这是新类'
        }
    }
}

@test('你好啊')
class A { }

const a: A = new A()

4.成员装饰器

4.1 属性装饰器

属性装饰器本质是一个函数,可以传递两个参数

  • 参数1
    • 当修饰静态成员时,该参数为构造函数本身(类本身)
      • 因为静态成员是添加在构造函数/类身上的
    • 当修饰实例成员时,该参数为原型对象
      • 因为实例成员是添加在原型上的
  • 参数2
    • 为字符串类型,固定为属性名称
function test() {
    return function (target: any, n: string) {
        console.log('target', target); // target {}
        console.log(target == A.prototype); // true
        console.log('n', n); // n name
    }
}

class A {
    // 修饰实例属性时
    @test()
    name: string = '张三'
}


function test() {
    return function (target: any, n: string) {
        console.log('target', target); // target [class A] { age: '12' }
        console.log(target == A); // true
        console.log('n', n); // n age
    }
}

class A {
    // 修饰静态属性时
    @test()
    static age: string = '12'
}

4.2 方法装饰器

方法装饰器本质是一个函数,可以接收三个参数

  • 参数1
    • 当修饰静态成员时,该参数为构造函数本身(类本身)
      • 因为静态成员是添加在构造函数/类身上的
    • 当修饰实例成员时,该参数为原型对象
      • 因为实例成员是添加在原型上的
  • 参数2
    • 为字符串类型,固定为方法名称
  • 参数3
    • 方法描述,类似Object.defineProperty的属性描述
function test() {
    return function (target: any, n: string, descriptor: PropertyDescriptor) {
        console.log('target', target); // target {}
        console.log(target == A.prototype); // true
        console.log('n', n); // n getHi
        console.log("descriptor", descriptor);
        /**
         * descriptor {
            value: [Function: getHi],
            writable: true,
            enumerable: false,
            configurable: true
          }
          */

    }
}

class A {
    // 修饰实例成员时
    @test()
    getHi() { }
}


function test() {
    return function (target: any, n: string, descriptor: PropertyDescriptor) {
        console.log('target', target); // target [class A]
        console.log(target == A); // true
        console.log('n', n); // n getHi
        console.log("descriptor", descriptor);
        /**
         * descriptor {
            value: [Function: getHi],
            writable: true,
            enumerable: false,
            configurable: true
            }
          */

    }
}

class A {
    // 修饰静态成员时
    @test()
    static getHi() { }
}

5.第三方库reflect-metadata

reflect-metadata可以用于元数据存储,可以结合装饰器使用

6.第三方校验库class-validator

class-validator可以结合装饰器进行表单校验

7.第三方库class-transformer

8.第三方帖子

nestJs学习-小满

9.装饰器调用顺序

  • 待补充