Проблема в том, что декораторы предназначены для применения к prototype
объекту. Если вы проверите проверенный js, вы поймете, почему он не работает.
class SomeClass {
@LogPerf()
public myMethod = (
data: MyData,
): Somehting => {
// Do something with data
}
}
/** transpiled to: */
class SomeClass {
constructor() {
this.myMethod = (data) => {
// Do something with data
};
}
}
__decorate([
LogPerf()
], SomeClass.prototype, "myMethod", void 0);
Видите, декоратор применяется к SomeClass.prototype["myMethod"]
. Однако, когда вы определяете ваш метод как функцию стрелки, он инициализируется в конструкторе и присваивается объекту this
.
Обходной путь будет:
- определить ваш метод как нормальную функцию на
prototype
объекте, затем связать this
при инициализации. - перегрузка
LogPerf()
подпись, чтобы принять альтернативное использование, подобное следующему:
class SomeClass {
public myMethod = LogPerf()((
data: MyData,
): Somehting => {
// Do something with data
})
}
Метод 1 может быть интегрирован в @LogPerf
декоратор, если вы предпочитаете. Вы можете использовать этот фрагмент кода из autobind-decorator
lib.
function boundMethod(target, key, descriptor) {
var fn = descriptor.value;
if (typeof fn !== 'function') {
throw new TypeError("@boundMethod decorator can only be applied to methods not: ".concat(_typeof(fn)));
} // In IE11 calling Object.defineProperty has a side-effect of evaluating the
// getter for the property which is being replaced. This causes infinite
// recursion and an "Out of stack space" error.
var definingProperty = false;
return {
configurable: true,
get: function get() {
// eslint-disable-next-line no-prototype-builtins
if (definingProperty || this === target.prototype || this.hasOwnProperty(key) || typeof fn !== 'function') {
return fn;
}
var boundFn = fn.bind(this);
definingProperty = true;
Object.defineProperty(this, key, {
configurable: true,
get: function get() {
return boundFn;
},
set: function set(value) {
fn = value;
delete this[key];
}
});
definingProperty = false;
return boundFn;
},
set: function set(value) {
fn = value;
}
};
}
Часть реализации метода 2 тривиальна, вам просто нужно обработать случай, когда только одна функция arg Я думаю, что вы можете понять это.
Сложная задача - как удовлетворить TypeScript, вот подпись функции, которая вам нужна:
export function LogPerf(message?: string): {
<T extends Function>(fn: T): T;
(target: Object, key: string | symbol, descriptor?: TypedPropertyDescriptor<any> | undefined): any;
}
export function LogPerf(message = '') {
// YOUR IMPLEMENTATION GOES HERE
}
Typescript Playground