Restrict function signatures in Typescript to only accept class or object methods

In my quest to create a function signature in Typescript, I am looking to develop a calling function that takes an object, its method name, and arguments to be applied.

Here is an example of it in action:

const obj = {
  do(...args) {
    console.log(args);
  }
}

call(obj, 'do', 1, 2, 3);

I've been pondering on a simple signature that would specify the second parameter as a property of the first object. However, I find it challenging to restrict all properties that are not methods and clarify that variadic arguments should be passed as this method's arguments.

function call<T, P extends keyof T, A extends any[]>(obj: T, property: P, ...args: A): void;

Do you think it is achievable with the current version of Typescript?

Answer №1

If we leverage the use of tuples in rest parameters, extracting the arguments of a function can be rather straightforward. TypeScript itself implements strict call, bind, and apply using this method (refer to this link).

By constraining the keys to only accept functions, we can define T as a record with keys that are functions:

const obj = {
    do(...args: string[]) {
        console.log(args);
    },
    other(o: string, n: number) {
        console.log(o);
    },
    prop: 1
}

function call<T extends Record<P, (...a: any[]) => any>, P extends keyof T>(obj: T, property: P, ...args: Parameters<T[P]>): ReturnType<T[P]> {
    return obj[property](...args);
}
call(obj, 'do', 1, 2, 3); // error
call(obj, 'do', '1'); // ok
call(obj, 'do', '1', '2'); // ok
call(obj, 'other', '1', 2); // ok
call(obj, 'prop'); // error

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

Improving my solution with PrimeNG in Angular2 - fixing the undefined tag error

After working with Angular for just three days, I successfully set up a login page dashboard using a web API solution. Everything was working great until I encountered an issue when trying to load the PrimeNG DataTableModule into my components. After searc ...

Error message TS2339 in Typescript: The property '__super__' is not found on the type '($element: any, options: any) => any'

Having trouble with Javascript code inside typescript. $.fn.select2.amd.require([ 'select2/data/array', 'select2/utils' ], function (ArrayData, Utils) { /* tslint:disable */ function CustomData ($element, opti ...

Errors related to missing RxJS operators are occurring in the browser, but are not showing up in Visual Studio

Recently, I encountered a peculiar problem with my Angular4 project, which is managed under Angular-CLI and utilizes the RxJS library. Upon updating the RxJS library to version 5.5.2, the project started experiencing issues with Observable operators. The s ...

The compiler is unable to locate the node_module (Error: "Module name not found")

Error: src/app/app.component.ts:4:12 - error TS2591: Cannot find name 'module'. Do you need to install type definitions for node? Try npm i @types/node and then add node to the types field in your tsconfig. 4 moduleId: module.id, When att ...

Tips on sorting an array within a map function

During the iteration process, I am facing a challenge where I need to modify certain values based on specific conditions. Here is the current loop setup: response.result.forEach(item => { this.tableModel.push( new F ...

What strategies can be utilized to manage a sizable data set?

I'm currently tasked with downloading a large dataset from my company's database and analyzing it in Excel. To streamline this process, I am looking to automate it using ExcelOnline. I found a helpful guide at this link provided by Microsoft Powe ...

The specified type '(Person | undefined)[]' cannot be assigned to the type 'People'

Encountering a typescript error while trying to update the state from the reducer: The error states: Type '(Person | undefined)[]' is not assignable to type 'People' reducer.ts: export type Person = { id: string; name: string; ph ...

Tips for Invoking an Overloaded Function within a Generic Environment

Imagine having two interfaces that share some fields and another interface that serves as a superclass: interface IFirst { common: "A" | "B"; private_0: string; } interface ISecond { common: "C" | "D"; private_1: string; } interface ICommo ...

What is the mechanism behind making a Promise appear synchronous when using a Proxy in JavaScript?

const handler: ProxyHandler<any> = { get: (target: Promise<any>, prop: string, receiver: any) => { return target.then((o) => { return o[prop].apply(o); }); }, }; return new Proxy(obj, handler) ...

Transferring an array of data across different screens within an Ionic 2 application

I am a newcomer to Ionic 2 and I am encountering difficulties when it comes to passing data between pages. Within my Home.ts file, there exists a global array containing certain numbers that have been calculated. My intention is to transfer this array to m ...

You are unable to call upon an object that may be of type 'undefined' in typescript

Among all the other inquiries on this topic, my issue lies with the typescript compiler seeming perplexed due to the following code snippet: if(typeof this[method] === "function"){ await this[method](req,res,next) } The error message I am en ...

Unable to retrieve values using any = {} in TypeScript Angular 8

import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { enableProdMode } from '@angular/core'; enableProdMode(); @Component({ selector: 'app-home', templat ...

Injecting a useFactory provider in Angular is a common practice

I manage a factory provider service that selects a service based on a flag. Everything works fine when I need a debug students service, but when I set the flag to false, the application throws an ERROR TypeError: serverService.fetchData is not a function. ...

The argument of type 'InputType[]' is incompatible with the parameter of type 'GenericType[]' in Typescript

In this scenario, I am developing a utility function with the objective of dynamically sorting an array of objects (the first parameter) in alphabetical order, based on a specified key passed as the second argument. The utility function is defined as foll ...

changing an array into json format using TypeScript

Looking to convert an array into JSON using TypeScript. How can I achieve the desired result shown below? let array = ['element1', 'element2', 'element3'] result = [{"value": "element1"}, {"value": "element2"}, {"value": "el ...

Separate an array in TypeScript based on the sign of each number, and then replace the empty spaces with null objects

Hey, I'm facing a little issue, I have an Array of objects and my goal is to split them based on the sign of numbers. The objects should then be dynamically stored in different Arrays while retaining their index and getting padded with zeros at the b ...

The issue arises as ContentChildren becomes undefined while trying to retrieve the data from the server

While I am loading data from the server and displaying it in ng-content, I am encountering an issue with making the first tab active by default. When using static content like the example below, the first tab is set as active without any problems: <app ...

Updating CSS class for a label when a radio button is selected in Angular 6

Within my Angular component, I've set up a radio button group like so: <label class="btn-{{cl1}}"> <input type="radio" value="am" name="time" formControlName="time1" (change)="cl1=active" >9:00am </label> I am looking for an effi ...

What is the reason for Jest attempting to resolve all components in my index.ts file?

Having a bit of trouble while using Jest (with Enzyme) to test my Typescript-React project due to an issue with an alias module. The module is being found correctly, but I believe the problem may lie in the structure of one of my files. In my jest.config ...

Using Angular to create a Mat table with the ability to select multiple rows

Trying to add shift click feature to a sorted MatDataTable using angular and typescript. When a click event occurs on the table, the selected row is stored. If a shift click is detected, it should select rows between the last selected and the current row ...