Как затипизировать декорируемый класс?

Для того чтобы затипизировать декорируемый класс в TypeScript, мы можем использовать параметр T в качестве обобщения (generic) для класса и указать тип этого обобщения при его декларации.

Декораторы в TypeScript - это функции, которые могут принимать различные аргументы и возвращать новый класс или функцию. Чтобы типизировать декорируемый класс, мы можем использовать обобщение на самом декораторе.

Давайте рассмотрим пример. У нас есть класс Person с двумя свойствами - name и age. Мы хотим добавить декоратор log к этому классу, который будет выводить в консоль информацию о создании нового объекта класса Person.

function log<T extends { new (...args: any[]): {} }>(constructor: T) {
  return class extends constructor {
    constructor(...args: any[]) {
      super(...args);
      console.log(`New instance of ${constructor.name} created`);
    }
  };
}

@log
class Person {
  name: string;
  age: number;

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

const person = new Person("John Doe", 25); // New instance of Person created
console.log(person.name); // John Doe
console.log(person.age); // 25

В приведенном выше примере мы определили декоратор log, который принимает класс constructor и возвращает новый класс, наследующийся от constructor. В конструкторе нового класса мы вызываем super(...args) для передачи аргументов конструктору оригинального класса.

Затем мы использовали декоратор log для класса Person. Теперь, при каждом создании нового экземпляра класса Person, будет выводиться сообщение в консоль.

Обобщение <T extends { new (...args: any[]): {} }> означает, что T должен быть классом, у которого есть конструктор с любым количеством аргументов и не имеющим возвращаемого значения (или с возвращаемым значением типа {}). Это позволяет нам использовать декоратор для любого класса, удовлетворяющего этим требованиям.

Таким образом, мы можем затипизировать декорируемый класс, используя обобщение в декораторе, и добавить кастомную логику в декоратор для дополнительной функциональности класса.