Extract Method Parameter Types in Typescript from a Generic Function

Can we retrieve the type of parameters of methods from a generic interface?

For instance, if we have:

interface Keys {
  create: any;
  ...
}

type MethodNames<T> = { [P in keyof Keys]: keyof T; }

Then, is it feasible to obtain the type of parameters for those methods?

type MethodParams<T> = { [P in keyof Keys]: Parameters<T[???]>; }

Playground Link to Relevant Code

Answer №1

To envision this concept working, MethodParams needs to be both generic not just in T, the underlying API type, but also in M, which represents the specific MethodNames<T> suitable for T. Here's how it could potentially look:

type Keys = "create" | "getOne" | "getAll" | "update" | "delete"

export type MethodNames<T> = {
  [K in Keys]: keyof T;
};

export type MethodParams<T, M extends MethodNames<T>> = {
  [K in Keys]: T[M[K]] extends (...args: infer P) => any ? P : never;
};

(Instead of an object type with ignored values of type any, I simplified Keys as a union of string literals.)

The function MethodParams<T, M> loops through the keys in Keys and fetches each key from M to retrieve the desired parameter key from T for analysis. This involves inferring within conditional types.


Let's put this theory to the test. Firstly, a helper function is needed to validate if a proposed method mapper functions correctly for a given type T:

const methods = <T, M extends MethodNames<T>>(api: T, methods: M) => methods;

Next, let's define a fictional API:

interface SomeData {
  id: number,
  a: string,
  b: number,
  c: boolean
}
interface SomeApi {
  change(id: number, data: Partial<SomeData>): SomeData,
  destroy(id: number): boolean
  grab(id: number): SomeData | undefined,
  grabbingSpree(): SomeData[],
  make(data: Omit<SomeData, "id">): SomeData,
}
declare const someApi: SomeApi;

Here's the method mapping:

const someApiMethods = methods(someApi, {
  create: "make",
  getOne: "grab",
  getAll: "grabbingSpree",
  update: "change",
  delete: "destroy"
})

Finally, test MethodParams:

type SomeApiMethodParams = MethodParams<SomeApi, typeof someApiMethods>;
/* The output should be:
{
    create: [data: Omit<SomeData, "id">];
    getOne: [id: number];
    getAll: [];
    update: [id: number, data: Partial<SomeData>];
    delete: [id: number];
} */

The expected result aligns with the type definition of SomeApiMethodParams.


This approach implies that any class or type utilizing MethodParams must be generic in the relevant MethodNames type. For instance, your AbstractTestEnv class would require an additional type parameter:

export abstract class AbstractTestEnv<S, T, U, M extends MethodNames<S>> {
  public api: S;       
  public createDto: T;
  public crudMethods: M;    
  protected constructor(api: S, crudMethods: M) {
    this.api = api;
    this.crudMethods = crudMethods;
    this.createDto = this.generateCreateDto(this.resourceId);
  }   
  public abstract generateCreateDto(resourceId: string): T;
  public abstract getParams(): MethodParams<S, M>;
  /* omitted code */
}

Link to Playground 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

Trouble with Styling React-Toastify in TypeScript: struggling to adjust z-index in Toast Container

Currently in the process of developing a React application utilizing TypeScript, I have incorporated the React-Toastify library to handle notifications. However, encountering some challenges with the styling of the ToastContainer component. Specifically, ...

combine two separate typescript declaration files into a single package

Can anyone help me figure out how to merge two typescript definition packages, @types/package-a and @types/package-b, into one definition package? package-a.d.ts [export package-a {...}] package-b.d.ts [exports package-b {...}] package-mine.d.ts [ export ...

Having trouble with the "Vs Code nx console generate" command? It seems that there are no flags available to configure

My issue involves the nx console extension installed in my Visual Studio Code. Every time I attempt to use the generate command for components, services, or libraries, I receive an error message stating "ng generate @schematics/angular:component This com ...

I'm having trouble grasping the issue: TypeError: Unable to access the 'subscribe' property of an undefined object

I've been working on a feature that involves fetching data from API calls. However, during testing, I encountered some errors even before setting up any actual test cases: TypeError: Cannot read property 'subscribe' of undefined at DataC ...

Receiving a reply from the axios function

Whenever I try to call the lookUpItem function from ItemSearch.vue, I always get an undefined response. Code snippet from ItemSearch.vue: <script setup lang="ts"> import { lookUpItem } from '../systemApi' async fu ...

Even as I create fresh references, my JavaScript array object continues to overwrite previous objects

Coming from a background in c# and c++, I am facing some confusion with a particular situation. Within the scope of my function, I am creating a new object before pushing it into an 'array'. Strangely, when I create the new object, it appears to ...

Importing TypeScript modules dynamically can be achieved without the need for Promises

I find myself in a scenario where the dynamic nature of these commands is crucial to prevent excessive loading of unnecessary code when executing specific command-line tasks. if (diagnostics) { require('./lib/cli-commands/run-diagnostics').run ...

Asynchronous and nested onSnapshot function in Firestore with await and async functionality

I'm facing an issue with the onSnapshot method. It seems to not await for the second onsnapshot call, resulting in an incorrect returned value. The users fetched in the second onsnapshot call are displayed later in the console log after the value has ...

Having trouble pinpointing the specific custom exception type when using the throw statement in TypeScript?

I have run into a problem while using a customized HttpException class in TypeScript. Let me show you how the class is structured: class HttpException extends Error { public status: number | undefined; public message: string; public data: any; ...

The type "AppRouterInstance" cannot be assigned to type "nextRouter"

Within my Next.js project, a registration form is included as seen below: "use client"; import * as React from "react"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form" ...

Unable to modify the border-radius property of Material UI DatePicker

I'm having difficulties setting rounded borders for my DatePicker component from @mui/x-date-pickers and Material UI V5. Here is the intended look I am aiming for: https://i.stack.imgur.com/c1T8b.png I've tried using styled components from Mat ...

Display options based on the value selected in the preceding selection

How can I dynamically display select options in an Angular select based on a previously selected value? Take a look at the code snippet below. Here, I have implemented a conditional display of select options (Target 1/Target 2) based on the value selected ...

The `Home` object does not have the property `age` in React/TypeScript

Hey there, I'm new to React and TypeScript. Currently, I'm working on creating a React component using the SPFX framework. Interestingly, I'm encountering an error with this.age, but when I use props.age everything seems to work fine. A Typ ...

Mastering Angular 2 Reactive Forms: Efficiently Binding Entire Objects in a Single Stroke

Exploring reactive forms in Angular 2 has led me to ponder the possibility of binding all object properties simultaneously. Most tutorials show the following approach: this.form = this.fb.group({ name: ['', Validators.required], event: t ...

Please ensure that the property name is a valid type, such as 'string', 'number', 'symbol', or 'any'

Can anyone help me convert this JavaScript file to Typescript? import React, { useState } from 'react'; import { Button } from './Button'; import { Link } from 'react-router-dom'; import './Navbar.css'; import Settin ...

Accessing files from various directories within my project

I'm working on a project with 2 sources and I need to import a file from MyProject into nest-project-payment. Can you please guide me on how to do this? Here is the current file structure of my project: https://i.stack.imgur.com/KGKnp.png I attempt ...

What is the best method to create a TypeScript dictionary from an object using a keyboard?

One approach I frequently use involves treating objects as dictionaries. For example: type Foo = { a: string } type MyDictionary = { [key: string]: Foo } function foo(dict: MyDictionary) { // Requirement 1: The values should be of type Foo[] const va ...

Is it possible for Typescript and Next.js to import a different project's *source code* only from the module's root directory?

Issue with Sharing React Components between Closed and Open Source Next.js Projects I am facing a challenge in my development setup involving two Next.js projects, one closed source (Project A) and the other open source (Project B). In Project A, which is ...

Organize routes into distinct modules in Angular 6

Currently grappling with routing in my Angular 6 application. Wondering if the structure I have in mind is feasible. Here's what it looks like: The App module contains the main routing with a parent route defining the layout: const routes: Routes = ...

Improving the method to change a string into a string literal in TypeScript

Utilizing a third-party tool that has specified editorStylingMode?: 'outlined' | 'underlined' | 'filled'; I have set the value in my environment.ts file (in Angular) as shown below export const environment = { productio ...