第44天:装饰师
#javascript #typescript #100daysofcode #day44

在本文中,我们将在打字稿中深入研究装饰者,探索他们的类型,并提供实用的例子以帮助您发挥其全部潜力。

什么是装饰师? ð -

在其核心上,装饰器只是使用@符号应用于类,方法,属性或参数的功能。它们可用于各种目的,包括:

  1. 记录和调试:在执行方法之前和之后添加记录语句。
  2. 验证:检查输入或输出的有效性。
  3. 授权:控制对某些方法或路线的访问。
  4. 回忆:缓存昂贵操作的结果。
  5. 依赖注入:自动将依赖项注入类。
  6. 元数据集合:存储有关类或属性的其他信息。

班级装饰师ð

班级装饰师应用于课程。他们将类构造函数作为其唯一参数,可用于修改类或向其添加元数据。

function MyDecorator(target: Function) {
  console.log('Class decorator called on', target);
}

@MyDecorator
class MyClass {
  constructor() {
    console.log('MyClass constructor');
  }
}

// Output:
// Class decorator called on [Function: MyClass]
// MyClass constructor

方法装饰师ð

方法装饰器被应用于类中的方法。他们接收三个参数:目标类原型,方法名称和属性描述符。

function LogMethod(target: Object, key: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args: any[]) {
    console.log(`Calling ${key} with arguments: ${args}`);
    const result = originalMethod.apply(this, args);
    console.log(`${key} returned: ${result}`);
    return result;
  };

  return descriptor;
}

class Calculator {
  @LogMethod
  add(a: number, b: number): number {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(2, 3);

// Output:
// Calling add with arguments: 2,3
// add returned: 5

物业装饰师ð

属性装饰器用于修改类中的属性。他们收到两个参数:目标类原型和属性名称。

function Validate(target: any, key: string) {
  let value = target[key];

  const getter = () => value;

  const setter = (newValue: any) => {
    if (typeof newValue !== 'number' || newValue < 0) {
      throw new Error('Invalid value');
    }
    value = newValue;
  };

  Object.defineProperty(target, key, {
    get: getter,
    set: setter,
  });
}

class Product {
  @Validate
  price: number;

  constructor(price: number) {
    this.price = price;
  }
}

const product = new Product(50);
product.price = -10; // Throws an error

// Output:
// Error: Invalid value

参数装饰器ð

参数装饰器应用于类中方法的参数。他们接收三个参数:目标类原型,方法名称和参数的索引。

const Injectable = (): ParameterDecorator => {
  return (target: any, key: string | symbol, index: number) => {
    // Register the dependency injection here
    console.log(`Injecting parameter at index ${index} in method ${key}`);
  };
};

class UserService {
  constructor(private readonly logger: Logger) {}

  @Injectable()
  log(message: string) {
    this.logger.log(message);
  }
}

const logger = new Logger();
const userService = new UserService(logger);
userService.log('Hello, Decorators!');

// Output:
// Injecting parameter at index 0 in method log
// Hello, Decorators!