Determining the response type of a method within a Typescript decorator through inference

I am seeking to extract the response type of a method that I apply a custom decorator to (specifically an old-style TypeScript experimental decorator, not the newer JS decorators). This is necessary in order to utilize the property names within the response as parameters within the decorator itself.

The code snippet below demonstrates my current approach:

type TaskProps<T, M> = {
  next: keyof T;
  param: ReturnType<M> extends {} ? keyof ReturnType<M> : string;
};

function Task<T, K extends keyof T>(props: TaskProps<T, T[K]>) {
  return function (target: T, propertyKey: K, descriptor: PropertyDescriptor) {
  };
}

class ExampleClass {
  @Task({
    next: "bye",
    param: "name",
  })
  hello() {
    return {
      name: "example",
      age: 11
    };
  }

  bye() {}
}

Upon attempting to assign the type M to the ReturnType, an error message stating:

Type 'M' does not satisfy the constraint '(...args: any) => any'.

Answer №1

For the purpose of this discussion, I will not delve deeply into the extensive topic of TypeScript decorators. This includes the distinction between TypeScript experimental decorators (currently used) and newer JavaScript decorators (not utilized here), or whether your decorator function accomplishes its intended functionality. My focus is solely on resolving the compiler error that you have inquired about.


The reported error '

Type 'M' does not satisfy the constraint '(...args: any) => any'
' indicates that the generic type parameter M is not restricted to a function type. It could be any data type such as string or Date. However, the ReturnType utility type mandates its type argument to be a function type. The simplest resolution is to properly constrain M:

type TaskProps<T, M extends (...args: any) => any> = {
    next: keyof T;
    param: ReturnType<M> extends {} ? keyof ReturnType<M> : string; // acceptable
};

Subsequently, extend this constraint to the Task function, similar to how it's done below:

function Task<
    T extends Record<K, (...args: any) => any>,
    K extends keyof T
>(props: TaskProps<T, T[K]>) {
    return function (target: T, propertyKey: K, descriptor: PropertyDescriptor) {
    };
}

This declaration signifies (using the Record utility type) that T contains a key of type

K</code with a corresponding function value, allowing the compiler to infer that the indexed access type <code>T[K]</code aligns with the second type argument of <code>TaskProps
and consequently to ReturnType.

Playground link for code demonstration

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

Unable to bring in Vue component from NPM module

Hello there, I recently developed my own npm package for a navigation bar and I need to incorporate it into my main codebase. Currently, I am utilizing vue @components but I am struggling with integrating the imported component. If anyone has insight on h ...

The type is lacking the following properties in array.push

Encountering an issue with the register page in my IONIC app. Currently, I am utilizing a data.json file to store all user data, and I aim to create a new member with minimal information required (name, email, password) while leaving other fields empty fo ...

ESLint is indicating an error when attempting to import the screen from @testing-library/react

After importing the screen function from @testing-library/react, I encountered an ESLint error: ESLint: screen not found in '@testing-library/react'(import/named) // render is imported properly import { render, screen } from '@testing-lib ...

What is the best approach to validating GraphQL query variables while utilizing Mock Service Worker?

When simulating a graphql query with a mock service worker (MSW), we need to verify that the variables passed to the query contain specific values. This involves more than just type validation using typescript typings. In our setup, we utilize jest along ...

How to correctly type socket events when developing a customized useSocket hook in TypeScript?

Both my socket server and socket client are set to listen for a specific range of events. Below are the definitions for these socket events: import { Server } from "socket.io"; import { Socket } from "socket.io-client"; import { Disconn ...

The value of form.formGroup is not equivalent to the output of console.log(form)

Having an issue here. When I send a Form to a component, If I use console.log(form), it displays the object correctly. However, when I check the form in the console, the form.formGroup.value looks fine (e.g. {MOBILE0: 'xxx', PHONE0: 'xxx&ap ...

Discovering the secrets of monitoring changes in children's length in React

Here is the code I am working with: const container = useRef(); const [items, setItems] = useState(); useEffect(()=>{ setItems(container.current.children.length); },[container.current, container.current.children.length]) return( <div ref={contain ...

Setting a TypeScript type recursively to allow for changes without affecting tuples

export type DraftObject<T> = {-readonly [P in keyof T]: Draft<T[P]>} export interface DraftArray<T> extends Array<Draft<T>> {} export type Draft<T> = T extends any[] ? DraftArray<T[number]> : T extends Read ...

Angular, Transforming JSON with RxJS Operators in TypeScript

Upon receiving the JSON object (Survey) from the server, it looked like this: { "id": 870, "title": "test survey", "questions": [ { "id": 871, "data": ...

Combine several .ts files into one bundle called package.js

Here is the structure of my code: Foo.ts: export module Foo { export function load() { } } Bar.ts: export module Bar { export function load() { } } webpack.config.js: const path = require('path'); module.exports = { entry: { ...

Error message: An unhandled TypeError occurs when attempting to access properties of an undefined object (specifically, the 'then' property) while refreshing the token using axios

Is there a way to refresh tokens in axios without interrupting the flow? For example, when the server returns an access token expiration error, I want to queue the request and replay it after getting a new token. In React, I'm using promises as shown ...

How to use a function as the redirectTo parameter in Angular 2+ routing

In my Angular application, I have set up the following route configuration: { path: ParentComponent.path, component: ParentComponent, canActivate: [AuthGuard], children: [ { path: '', pathMatch: 'full', re ...

The 'asObservable' property is not present on the type '() => any'.ts(2339)

Error: Property 'asObservable' does not exist on type '() => any'.ts(2339) Error: Property 'subscribe' does not exist on type 'Subscription'. Did you mean 'unsubscribe'?ts(2551) Error: Property 'sub ...

I am experiencing difficulties with implementing Angular material components in my project

I recently encountered an issue while trying to integrate angular material into my project. Despite importing the MatFormFieldModule, I received the following error: ERROR in src/app/login/components/login/login.component.html:2:1 - error NG8001: &apo ...

Corrected typing mistakes using vuex

Currently, I am working on a project using Vue 3 and TypeScript. One issue I am facing is related to vuex. I have created a file named vuex.d.ts to access $store inside Components: import { Store } from 'vuex'; import { State } from '@/stor ...

Altering the background color of an individual mat-card component in an Angular application

Here is the representation of my mat-card list in my Angular application: <div [ngClass]="verticalResultsBarStyle"> <div class="innerDiv"> <mat-card [ngClass]="barStyle" *ngFor="let card of obs | async | paginate: { id: 'paginato ...

Is the stepper's vertical line separating when the label extends onto multiple lines?

I'm facing an issue with the text inside my MaterialUI Stepper // StepLabel, where it sometimes wraps over multiple lines. Is there a way to keep the vertical StepConnectors attached to the StepIcons regardless of the number of lines of text in the l ...

Is it possible to export all types/interfaces from .d.ts files within multiple folders using index.ts in a React TypeScript project?

In my current React project, I am managing multiple configuration folders: -config -api/ |index.ts |types.d.ts -routes/ |index.ts |types.d.ts ... For example, in the api/index.ts file, I can import necessary types using import {SomeTyp ...

What is the reason behind installing both Typescript and Javascript in Next.js?

After executing the command npx create-next-app --typescript --example with-tailwindcss my_project, my project ends up having this appearance: https://i.stack.imgur.com/yXEFK.png Is there a way to set up Next.js with Typescript and Tailwind CSS without i ...

Executing multiple http post requests in Angular2 using a for loop

I've encountered an issue while attempting to upload multiple files with individual titles. The problem arises when sending requests to the server, as I'm trying to pass each file and its corresponding title one by one. I have an array called bin ...