javascript - JS TS bruk dekoratør på alle metoder/list opp klassemetoder
Jeg vil gjerne bruke en dekoratorfunksjon på alle metoder i en klasse slik at jeg kan erstatte:
class User {
@log
delete() {}
@log
create() {}
@log
update() {}
}
med
@log
class User {
delete() {}
create() {}
update() {}
}
Svar #1
Lag en klasse-dekoratør og oppgi egenskapene på målobjektets prototype.
For hver eiendom:
- Hent egenskapsbeskrivelsen.
- Sørg for at det er for en metode.
- Pakk inn beskriververdien i en ny funksjon som logger informasjon om metodekallet.
- Definer den endrede egenskapsbeskrivelsen tilbake til egenskapen.
Det er viktig å endre eienskapsbeskrivelsen fordi du ønsker å sikre at dekoratøren din fungerer godt sammen med andre dekoratører som endrer eienskapsbeskrivelsen.
function log(target: Function) {
for (const propertyName of Object.keys(target.prototype)) {
const descriptor = Object.getOwnPropertyDescriptor(target.prototype, propertyName);
const isMethod = descriptor.value instanceof Function;
if (!isMethod)
continue;
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log("The method args are: " + JSON.stringify(args));
const result = originalMethod.apply(this, args);
console.log("The return value is: " + result);
return result;
};
Object.defineProperty(target.prototype, propertyName, descriptor);
}
}
Metoder i basis klasse
Hvis du vil at dette også skal påvirke metodene i basisklassen, kan du ønske noe i denne retningen:
function log(target: Function) {
for (const propertyName in target.prototype) {
const propertyValue = target.prototype[propertyName];
const isMethod = propertyValue instanceof Function;
if (!isMethod)
continue;
const descriptor = getMethodDescriptor(propertyName);
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log("The method args are: " + JSON.stringify(args));
const result = originalMethod.apply(this, args);
console.log("The return value is: " + result);
return result;
};
Object.defineProperty(target.prototype, propertyName, descriptor);
}
function getMethodDescriptor(propertyName: string): TypedPropertyDescriptor<any> {
if (target.prototype.hasOwnProperty(propertyName))
return Object.getOwnPropertyDescriptor(target.prototype, propertyName);
// create a new property descriptor for the base class' method
return {
configurable: true,
enumerable: true,
writable: true,
value: target.prototype[propertyName]
};
}
}
Svar #2
For den som snubler over dette i fremtiden:
Jeg tok inspirasjon fra Davids svar og lagde min egen versjon. Senere gjorde jeg det om til en npm-pakke: https://www.npmjs.com/package/decorate-all
I OPs scenario ville det blitt brukt slik
@DecorateAll(log)
class User {
delete() {}
create() {}
update() {}
}
