One way of using standard Reflect functionality with decorators:
import { performance } from 'perf_hooks';
// common decorator
export function log() {
return (_target, propertyKey: string, descriptor: PropertyDescriptor) => {
const originalMethod = descriptor.value;
descriptor.value = async function (...args) {
const start = performance.now();
const result = await originalMethod.apply(this, args);
const finish = performance.now();
const ms = Math.round(finish - start);
console.log(`[${propertyKey}] ${ms}ms`);
return result;
};
return descriptor;
};
}
// Decorator to log class method or all class methods with Reflect
export function Log(): MethodDecorator & ClassDecorator {
return (target: any, key?: string, descriptor?: TypedPropertyDescriptor<any>) => {
if (descriptor) {
// method decorator
return log()(target, key, descriptor);
}
const methodNames = Reflect.ownKeys(target.prototype);
methodNames.forEach((methodName: string) => {
if (methodName !== 'constructor') {
const methodDescriptor = Reflect.getOwnPropertyDescriptor(target.prototype, methodName);
const modifiedMethodDescriptor = log()(target, methodName, methodDescriptor);
Reflect.defineProperty(target.prototype, methodName, modifiedMethodDescriptor);
}
});
// class decorator
return target;
};
}
Example:
@Log() // set logging for all Service class methods
class Service {
@Log() // set logging only for this method
handleTasks() {}
}
Reflect Documantation