一文讲清什么是TypeScript装饰器以及如何使用TypeScript装饰器

发布时间:2023年12月23日

TypeScript 装饰器是什么?

装饰器(Decorator)是TypeScript提供的一个高级语法,它类似于一种特殊类型的声明,可以附加到类声明,方法,访问符,属性或参数上。装饰器主要以函数的形式出现,运行在编译阶段,以实现对所修饰对象的行为的修改或增强。这是一个功能强大且在TypeScript编程中常用的特性。

TypeScript 装饰器有什么作用?

装饰器在 TypeScript 中的主要应用场景包括:

  1. 类装饰器:?可以观察、修改、或替换类定义。它在提供元编程能力方面特别有用,能够实现诸如依赖注入等高级概念。
  2. 方法装饰器:?可以监视、修改或者替换类的方法定义。这对于日志记录、性能监控、以及某些应用程序级别的业务逻辑(如记录操作者信息)有巨大的用处。
  3. 属性装饰器:?可以监视、修改或替换类的属性定义。比如实现类型检查,或者实现相关get/set方法等。
  4. 参数装饰器:?对类方法中的参数进行注解。
  5. 访问器装饰器:?用于装饰类的访问器,即类中的get与set方法。

如何使用 TypeScript 装饰器

装饰器的使用顺序是从外到内、由下至上。如果一个装饰器既可以应用到类上,也可以应用到类的方法、属性或参数上,那么对于这样的装饰器,它将首先应用到类上,然后是方法,接着是属性,最后是参数。

类装饰器的使用

通过定义一个包含正确签名的函数,你就能创建一个类装饰器。类装饰器的参数是构造函数。

// 定义装饰器
function LogClass(target: Function) {
  console.log(`New instance of ${target.name} class created.`);
}

// 使用装饰器修饰类
@LogClass
class MyClass {
  constructor() {
    console.log("This is MyClass constructor");
  }
}

在上述代码中,**@LogClass便是一个装饰器,它在 MyClass**类被实例化的时候会执行,此时控制台会打印出相关日志。

方法装饰器的使用

方法装饰器用于监视、修改或替换类方法的定义。

// 定义装饰器
function LogMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  console.log(`Method ${propertyKey} of class ${target.constructor.name} is called.`);
}

class MyClass {
  // 使用装饰器修饰方法
  @LogMethod
  myMethod() {
    console.log("This is myMethod");
  }
}

方法装饰器**@LogMethod 的参数包括:目标类原型、方法名、以及描述符。在上述代码中,每次**myMethod`方法被调用的时候,都会打印出相关日志。

属性装饰器的使用

在Typescript中,属性装饰器可以接收两个参数:

  1. 目标类的原型(对于静态成员则为类的构造函数),
  2. 该属性的名称。

我们可以根据自己的需要来定制属性装饰器。来看以下例子:

function logProperty(target: Object, key: string | symbol): any {
    let value = target[key];

    // 属性值的 getter
    const getter = function() {
        console.log(`Get: ${key} => ${value}`);
        return value;
    };

    // 属性值的 setter
    const setter = function(newVal: any) {
        console.log(`Set: ${key} => ${newVal}`);
        value = newVal;
    };

    // 删除原始属性,替换为 getter 和 setter
    if (delete target[key]) {
        Object.defineProperty(target, key, {
            get: getter,
            set: setter,
            enumerable: true,
            configurable: true
        });
    }
}

class MyClass {
    @logProperty
    public myProp: string;
}

在这段代码中,我们设计了一个属性装饰器 @logProperty,这个装饰器对于修饰的属性进行了监视,任何对属性的取值和赋值都将被打印出来。

参数装饰器的使用

参数装饰器是表示对类的构造函数,或者方法的参数进行装饰。参数装饰器会在运行时被调用,传入以下三个参数:

  1. 对于静态成员,是类的构造函数,对于实例成员,是类的原型对象。
  2. 成员的名字。(若装饰构造函数则为 undefined)
  3. 参数在函数参数列表中的索引。

请看以下示例:

function logParameter(target: Object, key: string | symbol, index: number) {
    console.log(`The decorator is applied to parameter: ${index} of method: ${key.toString()}`);
}

class MyClass {
    myMethod(@logParameter name: string) {
        return name;
    }
}

在上述代码中,@logParameter就是一个参数装饰器,它会在参数被使用时被调用并打印参数的索引和所在方法名。

访问器装饰器的使用

访问器是类的一个特性,主要分为get访问器和set访问器。在Typescript中,我们可以使用装饰器去装饰访问器。访问器装饰器和方法装饰器使用方式类似,仍然是分别接收目标类、访问器名、和描述符三个参数。

function logAccessor(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor<any>) {
    const originalGet = descriptor.get;

    descriptor.get = function() {
        console.log(`Get: ${key.toString()} => ${originalGet.call(this)}`);
        return originalGet.call(this);
    };
}

class MyClass {
    private _name: string;

    @logAccessor
    get name(): string {
        return this._name;
    }

    set name(name: string) {
        this._name = name;
    }
}

在这段代码中,@logAccessor就是一个访问器装饰器,除了原有的功能之外,还会在每次取值的时候打印出name的值。

TypeScript 项目开启装饰器

在?tsconfig.json?文件中,有一个叫?experimentalDecorators?的属性,你需要将其设置为?true,才能在 TypeScript 中启用装饰器。

{
    "compilerOptions": {
        "target": "es5",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true
    }
}

在这个示例中:

  • "target": "es5"?表示输出的 JavaScript 代码符合 ES5 标准。
  • "experimentalDecorators": true?表示启用装饰器。
  • "emitDecoratorMetadata": true?表示额外生成装饰器的元数据,在某些情况下使用装饰器时,这是必须的。

总结

装饰器在 TypeScript 中的应用场景非常广泛,可以为我们提供强大的编程工具,如类装饰器、方法装饰器、属性装饰器、参数装饰器和访问器装饰器等,使得我们可以在编译阶段进行诸如日志记录、性能计算、参数验证等多种复杂的操作,使用这些装饰器,我们可以保持代码的整洁和解耦,使程序更易于理解和维护。

文章来源:https://blog.csdn.net/m0_37890289/article/details/135172680
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。