Skip to content

Instantly share code, notes, and snippets.

@Pacheco95
Created April 7, 2025 18:06
Show Gist options
  • Save Pacheco95/9c3a15a704c2c95e15fc68dacf511c9f to your computer and use it in GitHub Desktop.
Save Pacheco95/9c3a15a704c2c95e15fc68dacf511c9f to your computer and use it in GitHub Desktop.
Typescript type safe proxy function and decorators
function isPromise(value: any): value is Promise<any> {
return (
value !== null &&
typeof value === "object" &&
typeof value.then === "function" &&
typeof value.catch === "function"
);
}
async function asyncFunction<T>(index: number, array: Array<T>) {
await new Promise((resolve) => setTimeout(resolve, 100));
return array.at(index);
}
function syncFunction<T>(index: number, array: Array<T>) {
return array.at(index);
}
function proxy<T extends (...args: any[]) => any>(fn: T): T {
return function (...args: Parameters<T>) {
const returnValue = fn(...args);
if (isPromise(returnValue)) {
return Promise.resolve(returnValue).then((resolvedValue) => {
console.log(`[${fn.name}] Returned value`, resolvedValue);
return resolvedValue;
});
}
console.log(`[${fn.name}] Returned value`, returnValue);
return returnValue;
} as T;
}
function proxyDecorator() {
return function <T extends (...args: any[]) => any>(
target: any,
propertyKey: string,
descriptor: TypedPropertyDescriptor<T>,
) {
const originalMethod = descriptor.value!;
descriptor.value = function (this: unknown, ...args: Parameters<T>) {
const returnValue = originalMethod.apply(this, args);
if (isPromise(returnValue)) {
return Promise.resolve(returnValue).then((resolvedValue) => {
console.log(`[${propertyKey} Returned value`, resolvedValue);
return resolvedValue;
});
}
console.log(`[${propertyKey}] Returned value`, returnValue);
return returnValue;
} as T;
return descriptor;
};
}
class ProxyDecoratorExample {
@proxyDecorator()
async asyncMethod<T>(a: number, l: Array<T>) {
await new Promise((resolve) => setTimeout(resolve, 100));
return l.at(a);
}
@proxyDecorator()
syncMethod<T>(a: number, l: Array<T>) {
return l.at(a);
}
}
(async () => {
const loggedAsyncFunction = proxy(asyncFunction);
const loggedSyncFunction = proxy(syncFunction);
const numbers = [1, 2, 3, 4];
await loggedAsyncFunction(0, numbers);
loggedSyncFunction(1, numbers);
const example = new ProxyDecoratorExample();
await example.asyncMethod(2, numbers);
example.syncMethod(3, numbers);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment