Creating a universal wrapper function to serve as a logging tool?

Currently, I am working on a generic JS function that can wrap any other function. The purpose of this wrapper is to execute the wrapped function, log the input and output events, and then return the output for "transparent" logging. However, as I attempt to transition this function to TypeScript while maintaining type information for both the wrapped function and its output, I am facing some complexity.

Here is my current progress:

const syncLogger = <T>(f: T) => (...args: unknown[]): ReturnType<T> => {
  let value;
  try {
    value = f(...args);
    functionLogger('info', f, value, ...args); //logging
  } catch (error) {
    functionLogger('error', f, error.message, ...args); //logging
    throw error;
  }
  return value;
};

and here is how it should be utilized:

const myLoggedFunction = syncLogger(originalFunction);

The main issue arises with the args, which are used as the input for functions. I am struggling to find a way to inform TypeScript that these arguments correspond precisely to the parameters of the original function being wrapped.

Answer №1

For a more versatile approach, I suggest making the syncLogger function generic in both the arguments tuple A and the return type R:

const syncLogger = <A extends any[], R>(f: (...a: A) => R) => (
  ...args: A
): R => {
  let value;
  try {
    value = f(...args);
    functionLogger("info", f, value, ...args); // actual logging
  } catch (error) {
    functionLogger("error", f, error.message, ...args); //actual logging
    throw error;
  }
  return value;
};

This modification allows for expected behavior:

function originalFunction(x: string, y: number): boolean {
  return (x <= y.toFixed())
}

const myLoggedFunction = syncLogger(originalFunction); // works fine
// const myLoggedFunction: (x: string, y: number) => boolean

const bool = myLoggedFunction("121", 123); // logs info: originalFunction, true, "121", 123
console.log(bool) // prints: true

In addition, TypeScript's support for higher-order type inference from generic functions starting with version 3.4 enables successful use cases even when the original function is generic:

const loggingItself = syncLogger(syncLogger);
// Prior to TS 3.4: 😢
// const loggingItself: (...args: any[]) => (...args: any[]) => {} 
// From TS 3.4 onwards: 😊
// const loggingItself: <A extends any[], R>(f: (...a: A) => R) => (...args: A) => R

I hope this information proves helpful. All the best!

Link to code

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Developing a databound listview in Ionic: A step-by-step guide

In the world of programming, each platform has its own way of handling lists. For example, Android uses RecyclerView, WPF uses ListView, and in Ionic, we have ion-list. If you have a list of strings like this: Animals:string[] = ["Dog", "Cat", "Human", "C ...

Does the Typescript compiler sometimes skip adding braces?

I am encountering a problem with compiling a specific section of code in my Angular2 project. public reloadRecords() { let step = (this.timeInterval.max - this.timeInterval.min) / this.recordsChartSteps; let data = new Array(this.recordsChartSteps ...

Retrieve new data upon each screen entry

After running a query and rendering items via the UserList component, I use a button in the UserList to run a mutation for deleting an item. The components are linked, so passing the deleteContact function and using refetch() within it ensures that when a ...

Transform TypeScript class into an object

Is there a way to transfer all values from one typescript class, Class A, to another matching class, Class B? Could there be a method to extract all properties of Class A as an object? ...

Understanding the significance of an exclamation point preceding a period

Recently, I came across this code snippet: fixture.componentInstance.dataSource!.data = []; I am intrigued by the syntax dataSource!.data and would like to understand its significance. While familiar with using a question mark (?) before a dot (.) as in ...

Struggling with sluggish performance on a certain project within VS Code

My experience with VS code has been excellent over the years, but I recently encountered a problem in one of my projects that caused a significant slowdown in performance. Strangely, other projects are working fine without any issues on VS code. I suspect ...

What could be causing the Intellisense errors in Visual Studio 2015 that say "Cannot find module 'angular2/core'"?

Currently, I am utilizing Visual Studio 2015 Update 1 in conjunction with TypeScript 1.8.5. Within my ASP.NET MVC 4.6 Web Application, Angular2 is being used. The TypeScript compile options have been configured with the following settings: <PropertyG ...

Having trouble getting my Angular project up and running - facing issues with dependency tree resolution (ERESOLVE)

Currently, I am in the process of following an Angular tutorial and I wanted to run a project created by the instructor. To achieve this, I referred to the steps outlined in the 'how-to-use' file: How to use Begin by running "npm install" within ...

Ionic 2: Unveiling the Flipclock Component

Can anyone provide guidance on integrating the Flipclock 24-hours feature into my Ionic 2 application? I'm unsure about the compatibility of the JavaScript library with Ionic 2 in typescript. I have searched for information on using Flipclock in Ionic ...

The argument provided is a string type, which cannot be assigned to a parameter expecting an object with a 'results' property of type string

When attempting to pass the result.nativeEvent.message to another function, I am encountering the error: Argument of type 'string' is not assignable to parameter of type '{ results: string; } on onUnityMessageController(result.nativeEvent.me ...

Create a class with additional attributes to support different types of options

I define a set of options represented by strings: export type Category = 'people' | 'projects' | 'topics' | 'tools' An index is declared as follows: interface Entry { ... } type IPostEntryIndex = { [name in Cate ...

TypeScript encounters a self-referencing type alias circularly

Encountering an issue with Typescript 3.6.3, specifically getting the error: Type alias 'JSONValue' circularly references itself. View code online here In need of assistance to resolve the circular reference in this specific version of TS (note ...

Accessing the currently operating WS server instance with NodeJS

After successfully setting up a basic REST API using NodeJS, ExpressJS, and routing-controllers, I also managed to configure a WebSocket server alongside the REST API by implementing WS. const app = express(); app.use(bodyParser.json({limit: "50mb"})); a ...

Formatting numbers in Angular 2 to include a space every three zeros in a money amount

Let's say I have the number 30000 and I want to format it as 30 000. What method should I use to achieve this? Here are more examples: 300000 -> 300 000, 3000000 -> 3 000 000. Just to clarify, this is not about using dots or commas, but rather reco ...

Unable to locate the Chart object within the chartjs-plugin-labels.js file

Hello there, I am currently working on an Angular project where I want to incorporate a chart plugin. To achieve this, I executed the following commands: npm install angular2-chartjs npm install chartjs-plugin-labels Following that, I imported it into my ...

Consolidating Typescript modules into a single .js file

Recently, I was able to get my hands on a TypeScript library that I found on GitHub. As I started exploring it, I noticed that there were quite a few dependencies on other npm packages. This got me thinking - is there a way to compile all these files int ...

What is the best method for retrieving GET parameters in an Angular2 application?

Is there a way in Angular2 to retrieve GET parameters and store them locally similar to how sessions are handled in PHP? GET Params URL I need to obtain the access_token before navigating to the Dashboard component, which makes secure REST Webservice cal ...

Setting various colors for different plots within a single chart: A step-by-step guide

I'm currently tackling a project that requires me to showcase two different plots on the same chart, one being a "SPLINE" and the other a "COLUMN". My aim is to assign distinct background colors to each of these plots. Please note that I am referring ...

UI and `setState` out of sync

Creating a website with forum-like features, where different forums are displayed using Next.js and include a pagination button for navigating to the next page. Current implementation involves querying data using getServerSideProps on initial page load, f ...

When using TypeScript, the tls.TLSSocket() function may trigger an error mentioning the absence of a "socket" parameter

Currently, I am in the process of building a basic IRC bot and using raw sockets to connect to the IRC server. Initially written in plain Javascript, I am now transitioning it to TypeScript. However, I have encountered an unusual issue when attempting to c ...