Enhancing TypeScript with Generic Proxyify Functionality

I'm attempting to enclose a basic interface provided through a type generic in order to alter the return value of each function within the interface.

For instance:

interface IBaseInterface {
  test(a?: boolean, b?: number): Promise<boolean>;
  anotherTest?(a?: number): Promise<number>;
}

// to...

interface IBaseInterfaceModified {
  test(a?: boolean, b?: number): Promise<boolean> | string;
  anotherTest?(a?: number): Promise<number> | string;
}

I have made an attempt using mapped types along with generics with no success. The closest I've come is as follows:

type TProxyify<T> = {
  [K in keyof T]: TProxy<T[K]>;
};

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type TProxy<T> = {
  (): ReturnType<T> | string;
};

export function wrapType<T>(): TProxyify<T> {
  return 1 as any;
}

const s = wrapType<IBaseInterface>();
// s.test() tooltip outputs -> test(): string | Promise<boolean>

However, the type inference system removes the BaseInterface.test argument names and types. Is there a way for me to achieve this where I can encapsulate a base interface, change the function return types, and still maintain the original base interface type suggestions (argument names, types, and order) intact?

Any help would be greatly appreciated. Thank you.

Answer №1

Below is the solution for version 3.0

If you need to change the return type of a function, you can follow a similar approach as shown in this example

type TProxyify<T> = {
    [K in keyof T]: AddReturnType<T[K], string>;
};

type IsValidArg<T> = T extends object ? keyof T extends never ? false : true : true;
type AddReturnType<T, TNewReturn> = T extends (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E, f: infer F,
g: infer G, h: infer H, i: infer I, j: infer J) => infer R ? (
    IsValidArg<J> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => R | TNewReturn :
    IsValidArg<I> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => R | TNewReturn :
    IsValidArg<H> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => R | TNewReturn :
    IsValidArg<G> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => R | TNewReturn :
    IsValidArg<F> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F) => R | TNewReturn :
    IsValidArg<E> extends true ? (a: A, b: B, c: C, d: D, e: E) => R | TNewReturn :
    IsValidArg<D> extends true ? (a: A, b: B, c: C, d: D) => R | TNewReturn :
    IsValidArg<C> extends true ? (a: A, b: B, c: C) => R | TNewReturn :
    IsValidArg<B> extends true ? (a: A, b: B) => R | TNewReturn :
    IsValidArg<A> extends true ? (a: A) => R | TNewReturn :
    () => R | TNewReturn
) : T

export function wrapType<T>(): TProxyify<T> {
    return 1 as any;
}

interface IBaseInterface {
    test(a?: boolean, b?: number): Promise<boolean>;
    anotherTest?(a?: number): Promise<number>;
}

const s = wrapType<IBaseInterface>();

let ss = s.test(undefined, undefined); // result will be string | Promise<boolean>

An important point to note about this method is that optional parameters become required when used, which results in them being of type A or undefined. Hence, the call to test is s.test(undefined, undefined); rather than s.test();

Furthermore, parameter names are not retained, potentially impacting code readability.

Edit

Subsequent to providing an initial response, TypeScript has introduced a more efficient solution to this issue. With the inclusion of Tuples in rest parameters and spread expressions, there is no longer a need for multiple overloads:

type TProxyify<T> = {
    [K in keyof T]: AddReturnType<T[K], string>;
};

type ArgumentTypes<T> = T extends (... args: infer U ) => any ? U: never;
type AddReturnType<T, TNewReturn> = T extends (...args: any[])=> infer R ? (...a: ArgumentTypes<T>) => TNewReturn | R : T;

export function wrapType<T>(): TProxyify<T> {
    return 1 as any;
}

interface IBaseInterface {
    test(a?: boolean, b?: number): Promise<boolean>;
    anotherTest?(a?: number): Promise<number>;
}

const s = wrapType<IBaseInterface>();

let ss = s.test(undefined, undefined); // result will be string | Promise<boolean>

This revised approach is concise and addresses various issues:

  • Optional parameters stay optional
  • Parameter names are preserved
  • Works effectively with any quantity of arguments

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

bring in all the files located within the Directory

Is there a way to import all CSS files from a specific folder without having to import each file individually? Looking to import assets/css/* ? <link href="<?php echo base_url(); ?>assets/css/*" rel="stylesheet"/> <title&g ...

Is it possible to trigger the alert message by utilizing this code snippet?

Is it possible to display a message using this function? var start_database = function() { alert('hello'); }; window.setTimeout(start_database, 1000); ...

Issue: Unhandled rejection TypeError: Unable to access properties of an undefined variable (retrieving 'data')

Currently, I am developing applications using a combination of spring boot for the backend and react for the frontend. My goal is to create a form on the client side that can be submitted to save data in the database. After filling out the form and attemp ...

unable to display data through the web service

The functionality of this code is correct, but it seems to not be displaying records. When the record is retrieved from the file and shown in an alert, everything works fine. $j().ready(function(){ var result =$j.ajax({ ...

How to implement hover effect to show child div within parent div using React.js

Hey there! I'm fairly new to working with react js and currently trying to add some animation to a nested div. The parent div, known as " portfolio-product-item ", showcases a featured image pulled from the WP REST API. Inside this parent div, there&a ...

Iterate through three images using the `background-image` property in my Div

Is there a way to modify a code that loops through images based on an Img source in order to work with the "background-image" property of a div? HTML <div id="section2"></div> CSS #section2 { background-image: 'url(..images/banner1.jp ...

What is causing the issue with dynamic special characters not functioning properly in my React router?

I am working with 3 components named App.js, SearchCategoryPage.js, and Home.js. However, when I click on the search icon, it does not navigate me to the search page. What could be the reason for this issue? App.js const outlet_id = useSelector((state) =& ...

Dynamic HTML DOM element name changes

One thing I'm considering is the process of dynamically changing element names in the DOM with JavaScript or jQuery when adding or removing child elements. For instance, if I decide to delete the second text box from a form that originally has three t ...

Obtain the URL for the JavaScript code that is currently running

Can anyone help me find the URL of the JavaScript currently being executed? I am aware of using window.location.href for the current page, but that doesn't necessarily provide the path to the script that is running. Any assistance would be greatly ap ...

Issue with Prettier AutoFormatting in a project that combines TypeScript and JavaScript codebases

Recently, I've started incorporating TypeScript into an existing JavaScript project. The project is quite large, so I've decided to transition it to TypeScript gradually. Below is a snippet from my eslintrc.js file: module.exports = { parser: ...

only one of the ng-bind-html elements on the page is functioning

I am currently working on an AngularJS application and encountered a problem with this block of code. Only the first ng-bind-html works for me: <div ng-bind-html='newsTitle'> <div ng-bind-html='newsDetail'></div> &l ...

Trouble with the display:none attribute in Firefox and Chrome

<tr style="height:5px" id="TRRSHeaderTrialBar" name="TRRSHeaderTrialBar" style='display:none'> <tr id="TREmail" name="TREmail" style="height:1px;" nowrap style='display:none'> Using the code snippet above to hide the bar w ...

The test is failing to execute the service mock promise due to an issue with the `

A problem has arisen while creating a mock for the BoardService. It appears that the .then function is not executing in the controller during testing, even though it works perfectly fine in the live application. Below is the test snippet: beforeEach(inje ...

Tapping on the invisible picture

I currently have a square image of a car with a transparent background. My goal is to make the car clickable so that when I click on it, it triggers an action. However, I also want the transparency around the car to allow clicks to go through and affect th ...

Controller Not Deserializing Ajax File Upload in MVC 5

There seems to be an issue with deserializing the data sent using the multipart/form-data type within an MVC 5 project. Despite appearing valid in Fiddler, the data is not being mapped into the controller method. While debugging, it is evident that all par ...

Get rid of the folder from the URL using an <a> tag

I have both an English and French version of my website located at: *website.com/fr/index.php *website.com/index.php Currently, I have a direct link to switch between the two versions: -website.com/fr/index.php -website.com/index.php. However, I ...

Using jQuery to retrieve the TD value

I'm attempting to retrieve the TD value using the Value attribute.... Let's say I have the following HTML markup: <td nowrap="nowrap" value="FO2180TL" class="colPadding" id="salesOrderNumber1">bla bla </td> So, I tried this- v ...

Automated library that refreshes the webpage instantly upon any server modifications

Seeking a Javascript solution to automatically refresh a webpage when the server version is updated. Update: I am aware of the technical aspects involved and how to implement this feature. However, I am interested in finding an existing solution that I ca ...

Having trouble displaying specific images on React Native, how can I resolve this issue?

I am currently developing a weather application that retrieves weather information and displays it using ForecastItem components. However, I have noticed that some of the components do not display the weather image randomly. On the Home screen, I use the ...

The Jquery .change() function refreshes the results just once

I am working on a form with 3 input fields named #first, #second, and #third, along with a fourth field labeled as #theResult. <div id="addFields"> <span id="addFieldsHeader">Add The Fields</span> <table style="margin:0 auto;"> ...