I've been working on developing a decorator that is specifically designed for methods of type void
or Promise<void>
.
class TestClass {
// compiles successfully
@Example()
test() {}
// should compile, but doesn't
@Example()
async testPromise() {}
// fails to compile as expected
@Example()
async testBad() {
return 'test';
}
// fails to compile as expected
@Example()
async testBadPromise() {
return 'test';
}
}
While I understand the approach to refine decorated types in general, I am struggling to create a union type that includes promises. The minimal example below works for void methods, but not for Promise<void>
:
type VoidFn = ((...args: any[]) => void) | ((...args: any[]) => Promise<void>);
const Example = () => (
target: any,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<VoidFn>,
) => {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
const result = originalMethod!.apply(this, args);
return result;
};
return descriptor;
};
Additional points if it can capture methods that might potentially return undefined
, such as
Promise<string | undefined>
. My specific goal is to catch, log, and handle errors without disrupting the method's flow. Ultimately, the desired functionality looks like this:
const ErrorCapture = () => (
target: any,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<VoidFn>,
) => {
const originalMethod = descriptor.value;
if (originalMethod) {
descriptor.value = function(this: any, ...args: any[]) {
const handleError = (error: any) => {
console.error(error);
// etc.
};
try {
const result = originalMethod.apply(this, args);
if (result instanceof Promise) {
return result.catch(handleError);
}
} catch (error) {
handleError(error);
}
};
return descriptor;
}
};