Snippets

TS Function Wrappers

Creating transparent type-safe typescript wrappers

TS

/**
 * A function that wraps the given function argument, returning
 * a new function that can be called in place of the original function.
 */
export function wrapper<FArgs extends any[], FReturn>(
  fn: (...args: FArgs) => FReturn
) {
  // Define the new function to replace the original one.
  function newFn(this: any, ...args: Parameters<typeof fn>) {
    // Invoke the original function
    const result = fn.apply(this, args);

    // Return the original function result
    return result;
  }

  // Copy properties from the wrapped function to new function
  Object.entries(Object.getOwnPropertyDescriptors(fn)).forEach(
    ([prop, descriptor]) => {
      Object.defineProperty(newFn, prop, descriptor);
    }
  );

  // Return the new function to be used in place of the wrapped function
  return newFn;
}
/**
 * A function that wraps the given function argument, returning
 * a new function that can be called in place of the original function.
 */
export function wrapper<FArgs extends any[], FReturn>(
  fn: (...args: FArgs) => FReturn
) {
  // Define the new function to replace the original one.
  function newFn(this: any, ...args: Parameters<typeof fn>) {
    // Invoke the original function
    const result = fn.apply(this, args);

    // Return the original function result
    return result;
  }

  // Copy properties from the wrapped function to new function
  Object.entries(Object.getOwnPropertyDescriptors(fn)).forEach(
    ([prop, descriptor]) => {
      Object.defineProperty(newFn, prop, descriptor);
    }
  );

  // Return the new function to be used in place of the wrapped function
  return newFn;
}

Examples

trace

A simple type-safe wrapper to trace the execution of a function

TS

/**
 * Traces the execution of the given function, logging its
 * arguments and duration.
 */
export function trace<FArgs extends any[], FReturn>(
  fn: (...args: FArgs) => FReturn
) {
  function newFn(this: any, ...args: FArgs) {
    const tag = `${fn.name}(${args}) | duration`;

    console.time(tag);
    const result = fn.apply(this, args);
    console.timeEnd(tag);

    return result;
  }

  Object.entries(Object.getOwnPropertyDescriptors(fn)).forEach(
    ([prop, descriptor]) => {
      Object.defineProperty(newFn, prop, descriptor);
    }
  );

  return newFn;
}
/**
 * Traces the execution of the given function, logging its
 * arguments and duration.
 */
export function trace<FArgs extends any[], FReturn>(
  fn: (...args: FArgs) => FReturn
) {
  function newFn(this: any, ...args: FArgs) {
    const tag = `${fn.name}(${args}) | duration`;

    console.time(tag);
    const result = fn.apply(this, args);
    console.timeEnd(tag);

    return result;
  }

  Object.entries(Object.getOwnPropertyDescriptors(fn)).forEach(
    ([prop, descriptor]) => {
      Object.defineProperty(newFn, prop, descriptor);
    }
  );

  return newFn;
}

© 2021-2024 Rexford Essilfie. All rights reserved.