Реализация декоратора JS для обертывания класса
Я пытаюсь обернуть конструктор класса и ввести некоторую логику с помощью декоратора класса. Все работало нормально, пока я не попытался расширить обернутый класс: у расширенного класса нет методов в прототипе.
function logClass(Class) {
// save a reference to the original constructor
const _class = Class;
// proxy constructor
const proxy = function(...args) {
const obj = new _class(...args);
// ... add logic here
return obj
}
// copy prototype so intanceof operator still works
proxy.prototype = _class.prototype;
// return proxy constructor (will override original)
return proxy;
}
@logClass
class Base {
prop = 5;
test() {
console.log("test")
}
}
class Extended extends Base {
test2() {
console.log("test2")
}
}
var base = new Base()
base.test()
var ext = new Extended()
console.log(ext.prop)
ext.test()
ext.test2() // TypeError: ext.test2 is not a function
1 ответ
Итак, я попытался выяснить, что "не так" в вашем коде, но мне не удалось заставить его работать, потому что он не проверял тип. Итак, в крайнем случае, я публикую частичный ответ о своей попытке, который работает (с некоторыми причудами), поэтому я могу помочь другим пользователям, которые более сообразительны с TypeScript.
Прежде всего, причуды: декораторы классов в TS не могут изменять структуру типа, поэтому, если вы хотите, например, добавить метод в украшенный класс, вы сможете это сделать, но вам придется съесть / подавлять неизбежные ошибки типа (TS2339) при вызове этих методов.
В этом другом вопросе есть обходной путь: методы добавления Typescript с типом декоратора не существуют, но вы потеряете этот текущий чистый синтаксис для декораторов, если сделаете это.
Теперь мое решение, взятое более или менее прямо из документации:
function logClass<T extends { new(...args: any[]): {} }>(constructor: T) {
return class extends constructor {
constructor(...args: any[]) {
super(args);
// ...add programmatic logic here
// (`super` is the decorated class, of type `T`, here)
}
// ...add properties and methods here
log(message: string) { // EXAMPLE
console.log(`${super.constructor.name} says: ${message}`);
}
}
}
@logClass
class Base {
prop = 5;
test() {
console.log("test");
}
constructor() {}
}
class Extended extends Base {
test2() {
console.log("test2");
}
}
var base = new Base();
base.test();
var ext = new Extended();
console.log(ext.prop);
//base.log("Hello"); // unavoidable type error TS2339
ext.test();
ext.test2();