返回

TypeScript 入门学习——类以及类的装饰器

前端

TypeScript 类与装饰器简介

TypeScript中的类与传统JavaScript中的类非常相似,它们都可以定义属性和方法。不同之处在于,TypeScript中的类是强类型的,并且支持访问控制和继承。TypeScript中的装饰器是一种元编程技术,允许我们在类声明和成员(例如,方法、属性和访问器)上附加额外信息。这些信息可以通过运行时反射进行访问和使用,从而可以对类的行为进行修改或扩展。

类装饰器

类装饰器用于修饰整个类,它可以用来为类添加元数据、修改类的行为,或添加额外的特性。

类装饰器的语法

@decorator
class MyClass {
  // ...
}

在这个例子中,@decorator是装饰器,它被用于修饰MyClass类。装饰器可以是函数或类。

类装饰器的示例

以下是类装饰器的一些示例:

  • 日志装饰器 :该装饰器用于在类的方法执行前后打印日志。
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function(...args: any[]) {
    console.log(`Calling ${propertyKey} with args ${args}`);
    const result = originalMethod.apply(this, args);
    console.log(`Called ${propertyKey} with result ${result}`);
    return result;
  };
}

@log
class MyClass {
  sayHello(name: string) {
    return `Hello, ${name}!`;
  }
}

const myClass = new MyClass();
myClass.sayHello("World");
  • 属性校验装饰器 :该装饰器用于检查属性的值是否符合预期的条件。
function validate(condition: Function) {
  return function(target: any, propertyKey: string) {
    const descriptor = Object.getOwnPropertyDescriptor(target, propertyKey);
    if (descriptor) {
      const originalSet = descriptor.set;
      descriptor.set = function(value: any) {
        if (condition(value)) {
          originalSet?.call(this, value);
        } else {
          throw new Error("Invalid value");
        }
      };
    }
  };
}

class MyClass {
  @validate((value: number) => value >= 0)
  private _age: number;

  get age() {
    return this._age;
  }

  set age(value: number) {
    this._age = value;
  }
}

const myClass = new MyClass();
myClass.age = 20;
console.log(myClass.age); // 20

myClass.age = -1;
console.log(myClass.age); // Error: Invalid value

方法装饰器

方法装饰器用于修饰类中的方法,它可以用来在方法执行前后添加逻辑、修改方法的行为,或添加额外的特性。

方法装饰器的语法

class MyClass {
  @decorator
  methodName(args: any) {
    // ...
  }
}

在这个例子中,@decorator是装饰器,它被用于修饰methodName方法。装饰器可以是函数或类。

方法装饰器的示例

以下是方法装饰器的一些示例:

  • 计时装饰器 :该装饰器用于计算方法的执行时间。
function timing(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;
  descriptor.value = function(...args: any[]) {
    const start = performance.now();
    const result = originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`Method ${propertyKey} took ${end - start} milliseconds to execute.`);
    return result;
  };
}

class MyClass {
  @timing
  sayHello(name: string) {
    return `Hello, ${name}!`;
  }
}

const myClass = new MyClass();
myClass.sayHello("World");
  • 参数校验装饰器 :该装饰器用于检查方法参数的值是否符合预期的条件。
function validate(condition: Function) {
  return function(target: any, propertyKey: string, parameterIndex: number) {
    const originalMethod = target[propertyKey];
    target[propertyKey] = function(...args: any[]) {
      if (condition(args[parameterIndex])) {
        return originalMethod.apply(this, args);
      } else {
        throw new Error("Invalid argument");
      }
    };
  };
}

class MyClass {
  method(
    @validate((value: number) => value >= 0)
    x: number,
    @validate((value: number) => value < 10)
    y: number
  ) {
    return x + y;
  }
}

const myClass = new MyClass();
myClass.method(5, 3); // 8

myClass.method(5, 11); // Error: Invalid argument

属性装饰器

属性装饰器用于修饰类中的属性,它可以用来在属性访问时添加逻辑、修改属性的行为,或添加额外的特性。

属性装饰器的语法

class MyClass {
  @decorator
  propertyName: type;
}

在这个例子中,@decorator是装饰器,它被用于修饰propertyName属性。装饰器可以是函数或类。

属性装饰器的示例

以下是属性装饰器的一些示例:

  • 只读装饰器 :该装饰器用于将属性设置为只读。
function readOnly(target: any, propertyKey: string) {
  const descriptor = Object.getOwnPropertyDescriptor(target, propertyKey);
  if (descriptor) {
    descriptor.writable = false;
  }
}

class MyClass {
  @readOnly
  name: string;

  constructor(name: string) {
    this.name = name;
  }
}

const myClass = new MyClass("John");
myClass.name = "Mary"; // Error: Cannot assign to read only property 'name'
  • 类型检查装饰器 :该装饰器用于检查属性值是否符合预期的类型。
function checkType(type: Function) {
  return function(target: any, propertyKey: string) {
    const descriptor = Object.getOwnPropertyDescriptor(target, propertyKey);
    if (descriptor) {
      const originalSet = descriptor.set;
      descriptor.set = function(value: any) {
        if (typeof value === type) {
          originalSet?.call(this, value);
        } else {
          throw new Error("Invalid type");
        }
      };
    }
  };
}

class MyClass {
  @checkType(String)
  name: string;

  constructor(name: string) {
    this.name = name;
  }
}

const myClass = new MyClass("John");
myClass.name = "Mary"; // OK

myClass.name = 123; // Error: Invalid type

访问器装饰器

访问器装饰器用于修饰类中的访问器,它可以用来在访问器访问时添加逻辑、修改访问器行为,或添加额外的特性。

访问器装饰器的语法

class MyClass {
  @decorator
  get propertyName(): type;

  @decorator
  set propertyName(value: type);
}

在这个例子中,@decorator是装饰器,它被用于修饰propertyName访问器。装饰器可以是函数或类。

访问器装饰器的示例

以下是访问器装饰器的一些示例:

  • 只读访问器装饰器 :该装饰器用于将访问器设置为只读。
function readOnly(target: any, propertyKey: string) {
  const descriptor = Object.getOwnPropertyDescriptor(target, propertyKey);
  if (descriptor) {
    descriptor.set = undefined;
  }
}

class MyClass {
  @readOnly
  get name(): string {
    return this._name;
  }

  private _name: string;

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

const myClass = new MyClass("