自学内容网 自学内容网

【TypeScript入坑】TypeScript 的装饰器


装饰器

简介

装饰器(Decorator)是一种语法结构,用来在定义时修改类(class)的行为。

在语法上,装饰器有如下几个特征。

  1. 第一个字符(或者说前缀)是@,后面是一个表达式。
  2. @后面的表达式,必须是一个函数(或者执行后可以得到一个函数)。
  3. 这个函数接受所修饰对象的一些相关值作为参数。
  4. 这个函数要么不返回值,要么返回一个新对象取代所修饰的目标对象。

🤏 举个栗子,有一个函数 simpleDecorator() 当作装饰器使用,那么需要写成@simpleDecorator,然后放在某个类的前面。

function simpleDecorator(target: any, context: any) {
  console.log("hi, this is " + target);
  return target;
}

@simpleDecorator
class A {} // "hi, this is class A {}"

装饰器的结构

👇 装饰器函数的类型定义如下。

type Decorator = (
  value: DecoratedValue,
  context: {
    kind: string;
    name: string | symbol;
    addInitializer?(initializer: () => void): void;
    static?: boolean;
    private?: boolean;
    access: {
      get?(): unknown;
      set?(value: unknown): void;
    };
  }
) => void | ReplacementValue;

👇 解释:

  • value:所装饰的对象
  • context:上下文对象
    • kind:字符串,表示所装饰对象的类型
    • name:字符串或Symbol值,所装饰对象的名字
    • addInitializer():函数,用来添加类的初始化逻辑
    • private:布尔值,判断所装饰的对象是否为类的私有成员
    • static:布尔值,所装饰对象是否为类的静态成员。
    • access:一个对象,包含了某个值的getset方法。

类装饰器

👇 类装饰器的类型描述如下。

type ClassDecorator = (
  value: Function, // 当前类本身
  context: {
    kind: "class";
    name: string | undefined;
    addInitializer(initializer: () => void): void;
  } // 上下文对象
) => Function | void;

类装饰器一般用来对类进行操作,可以不用返回任何值。

function Greeter(value, context) {
  if (context.kind === "class") {
    value.prototype.greet = function () {
      console.log("你好");
    };
  }
}

@Greeter
class User {}

let u = new User();
u.greet(); // "你好"

类装饰器可以返回一个函数,替代当前类的构造方法。也可以返回一个新的类,替代原来所装饰的类。

方法装饰器

👇 方法装饰器用来装饰类的方法method)。它的类型描述如下。

type ClassMethodDecorator = (
  value: Function,
  context: {
    kind: "method";
    name: string | symbol;
    static: boolean;
    private: boolean;
    access: { get: () => unknown };
    addInitializer(initializer: () => void): void;
  }
) => Function | void;

如果方法装饰器返回一个新的函数,就会替代所装饰的原始函数。

function replaceMethod() {
  return function () {
    return `How are you, ${this.name}?`;
  };
}

class Person {
  constructor(name) {
    this.name = name;
  }

  @replaceMethod
  hello() {
    return `Hi ${this.name}!`;
  }
}

const robin = new Person("Robin");

robin.hello(); // 'How are you, Robin?'

属性装饰器

属性装饰器用来装饰定义在类顶部的属性field)。它的类型描述如下。

type ClassFieldDecorator = (
  value: undefined,
  context: {
    kind: "field";
    name: string | symbol;
    static: boolean;
    private: boolean;
    access: { get: () => unknown; set: (value: unknown) => void };
    addInitializer(initializer: () => void): void;
  }
) => (initialValue: unknown) => unknown | void;

属性装饰器要么不返回值,要么返回一个函数,该函数会自动执行,用来对所装饰属性进行初始化。该函数的参数是所装饰属性的初始值,该函数的返回值是该属性的最终值。

function logged(value, context) {
  const { kind, name } = context;
  if (kind === "field") {
    return function (initialValue) {
      console.log(`initializing ${name} with value ${initialValue}`);
      return initialValue;
    };
  }
}

class Color {
  @logged name = "green";
}

const color = new Color();
// "initializing name with value green"

getter装饰器,setter装饰器

getter 装饰器和 setter 装饰器,是分别针对类的取值器(getter)和存值器(setter)的装饰器。它们的类型描述如下。

这两个装饰器要么不返回值,要么返回一个函数,取代原来的取值器或存值器。

accessor装饰器

装饰器语法引入了一个新的属性修饰符 accessor

class C {
  accessor x = 1;
}

上面代码中,accessor 修饰符等同于为属性x自动生成取值器和存值器,它们作用于私有属性x。也就是说,上面的代码等同于下面的代码。

class C {
  #x = 1;

  get x() {
    return this.#x;
  }

  set x(val) {
    this.#x = val;
  }
}

装饰器的执行顺序

装饰器的执行分为两个阶段。

  1. 评估(evaluation):计算 @ 符号后面的表达式的值,得到的应该是函数。
  2. 应用(application):将评估装饰器后得到的函数,应用于所装饰对象。

也就是说,装饰器的执行顺序是,先评估所有装饰器表达式的值,再将其应用于当前类。

应用装饰器时,顺序依次为方法装饰器和属性装饰器,然后是类装饰器

分享一个: https://juejin.cn/post/7006483808832716813


原文地址:https://blog.csdn.net/XH_jing/article/details/142384716

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!