What is the best method for consolidating all parameter types of an object comprised of a collection of functions?

Can you analyze this typescript code snippet for me?

type params1 = {p:number} ;
type params2 = {p:boolean};
type params3 = {p:string};
type res = {r:string};

const fObject = {
a:(a:params1):res=>{return {r:`${a.p}`}},
b:(a:params2):res=>{return {r:`${a.p?1:0}`}},
c:(a:params3):res=>{return {r:a.p}}
}

Is it possible to define a type similar to the following?

type params = params1 | params2 | params3

I am planning to create a new object that includes all the functions from fObject, while also implementing a logger function on the result of each function.

It would look something like this:

const loggingObject: typeof fObject = Object.keys(fObject).reduce(
 (result: any, key: string) => {
   result[key] = (args: any/*reason for Q*/) => logger.report(fObject
  [key as loggingObject](args /*If i put something like 2 it says it has no properties in common with params1 & param2 & param3, thats why I know its possible*/));
   return result;
  },
  {},
);

I want to avoid using the any type and instead require a dynamic type that can accept an object with functions and determine the union of parameter types of all the functions within the object

Answer №1

This question is fantastic! There are actually multiple ways to achieve this. In the solution below, we will be using the following techniques:

If you need more detailed information, consider checking out the provided links for a deeper dive. By the end of it, we'll have a type that functions like this:

// Implement your code here...
type MyParams = ParamForKeys<typeof fObject>;
// => `type MyParams = param1 | param2 | param3`

Our approach involves mapping over the keys of fObject and substituting each key with the argument type of its corresponding function. This mapping operation looks something like this:

type MyParams<T> = { [key in keyof T]: ... }

The next step is to extract the argument type using Conditional Types. With these conditional types, we can set conditions and extract arguments through inference by utilizing the infer keyword:

type UnwrapPromise<T> = T extends Promise<infer Inner> ? Inner : never;
type A = UnwrapPromise<Promise<number>> // => number
type B = UnwrapPromise<number> // => never

We employ a similar method:

type GetFirstParam<T> = T extends ((param: infer Param) => any) ? Param : never

Combining these components gives us:

type GetFirstParam<T> = T extends ((param: infer Param) => any) ? Param : never
type ParamForKeys<T> = { [key in keyof T]: GetFirstParam<T[key]> }

This yields the type:

type MyParams = ParamForKeys<typeof fObject>;
// { a: param1, b: param2, c: param3 }

To convert the values into a union format (param1 | param2 | param3), access them as follows:

type GetFirstParam<T> = T extends ((param: infer Param) => any) ? Param : never
type ParamForKeys<T> = { [key in keyof T]: GetFirstParam<T[key]> }[keyof T]

That concludes the solution. Please note that while this may align with your requirements (using {a: param1, b:param2}), it depends on your specific needs concerning logging. Nonetheless, this should address your inquiry!

I hope this explanation was helpful. You can explore a live demonstration in this TypeScript playground.

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

Protractor Encounters Error When Assigning Variable

var itemStatus = element(by.model('item.statusId')).getText(); This issue is causing Protractor to raise an error: Uncaught exception: Error while waiting for Protractor to sync with the page: "Angular could not be found on the window" Pro ...

"Implement a function in Node.js/JavaScript that creates a new JSON object if the ID matches with the ID of another

const data = [ { system: { id: "4gSSbjCFEorYXqrgDIP2FA", type: "Entry", content: { type: { name: "Author" } }, }, DataDetails: { shortSlugOption: { "en-us": "some value", "za-op": "random value" }, ...

Contrasting Dependency Injection with Exporting Class Instances

I've been diving into the world of TypeScript and working on enhancing my skills as a web developer. One project I'm currently focused on is a simple ToDo app, which you can find here: https://github.com/ludersGabriel/toDo/tree/dev/backend. My q ...

Breaking down nested arrays in typescript

After receiving a response from the service, the data included the following: "rows": [ [ "stravi/aa", "202001", "59", "51", "2558.98", "0.5358894453719162", "1.9204668112983725", "140", "2.346630 ...

Can the Vue instance be accessed in Axios interceptors?

I've integrated vue-reactive-storage to have a reactive alternative to localStorage in my Vue application. This plugin creates a vue object that is accessible to all components. I'm facing an issue when trying to access this object within my axio ...

Using react-select to display "N items selected" instead of listing out all the selected items

Exploring the potential of react-select as a city-picker selector for users to choose one or multiple cities to filter data. Take a look at how it appears on my page: https://i.sstatic.net/A3cBX.png The list of cities may be extensive, and I am concerned ...

Learn the process of integrating VueJS with RequireJS

I am attempting to set up VueJS with RequireJS. Currently, I am using the following VueJS library: . Below is my configuration file for require: require.config({ baseUrl : "js", paths : { jquery : "libs/jquery-3.2.1.min", fullcalendar : "libs/ful ...

What is the reason for prioritizing a route without path parameters before a path with path parameters?

Running my code in a certain way resulted in errors like castError: cast to object failed for value new app.get("/products/:id", async (req, res) => { const { id } = req.params; const product = await Product.findById(id); res.rende ...

What could be the reason for the `controller.$render` method not being triggered as intended?

Check out this code snippet on plnkr.co. Within the link function of the directive, calling controller.$render() was successful. However, when attempting to override the controller.$render function, it does not execute as expected. The statement console.lo ...

Guide on executing get, modify, append, and erase tasks on a multi-parameter JSON array akin to an API within Angular

I have a JSON array called courseList with multiple parameters: public courseList:any=[ { id:1, cName: "Angular", bDesc: "This is the basic course for Angular.", amt: "$50", dur: & ...

Executing system commands using Groovy is a breeze

One of the scripts I have is a sample.js script that allows me to view files located on the server myHost. It works perfectly: var exec = require('ssh-exec') var v_host = 'myHost' exec('ls -lh', { user: 'username&apo ...

Angular 6: Harnessing the Power of Subject

In my angular applications, I have been utilizing the Subject feature from the rxjs library to create an event emitter. However, upon migrating to Angular 6, I encountered the issue that this module is no longer available. Cannot find module 'rxjs/Su ...

Add HTML or append a child element when clicking, then remove it from the previously clicked element

Within a container, I have several div elements where .div-to-hide is shown by default and .div-to-show is hidden. My goal is to toggle the visibility of these elements - when clicking on a .set, .div-to-hide should hide and .div-to-show should become vis ...

"Having trouble implementing sorting functionality on a click event in a React application with Material-UI table

Default behavior displays data in ascending order. Clicking on the table header should toggle between descending and ascending orders. Load Data in ascending order -> On click, change to descending order -> Again on click, change to ascending -> ...

Show the login page first before allowing the comment to be submitted in PHP

My objective is to show the login page before allowing a user to submit a comment. If the user is not logged in and tries to click on the submit button, they should be redirected to the login page. However, if the user is already logged in, the comment s ...

What can I do to enhance the performance of my password?

Exploring React for the first time and currently working on a registration page, I've run into a performance glitch with my password validation function. Check out the code below: State Declarations const [errorDiv, setErrorDiv] = useState(0); ...

Div with Sticky Header and Scrolling Ability

I am working on a project that involves creating a scrollable div with "title" elements inside. I want the title element of each section to stick to the top of the div as I scroll, similar to how a menu sticks to the top of a webpage. An example of this ca ...

Implementing Server-Side API Response Caching in React-Query and Next JS

My server-side rendering setup with react-query is working smoothly. I am aware that react-query stores a cache on the client side to serve data if the query key is fresh and available. Here is the code snippet depicting this setup - // pages/_app.tsx imp ...

Having trouble with Firebase continuously replacing old images with new ones whenever I upload them using JavaScript/jQuery

I am experiencing an issue with Firebase where it overrides my old pictures every time I upload a new picture. How can I configure it to save my old pictures as well? <!DOCTYPE html> <html> <head> <title>Firebase Storage< ...

I'm looking for the documentation for the latest version of Footable's Events. Can you point me

Does anyone know where to find information on the events that are fired for Footable and how to handle them? I checked the documentation at , but it doesn't provide much detail on events. If you have any resources or suggestions, please let me know! ...