The react decorator for maintaining type safety fails to identify the appropriate ReturnType of the supplied function

I want to enhance the redux connect feature by using it as a decorator for a specific reducer/state. Although I know that redux connect can already be used as a decorator, I am curious about why my custom implementation does not work the way I expect.

Here is the Higher Order Component (HOC) that I am currently using as a decorator:

interface InjectedProps { userId: string; }
type ComponentType<P> = React.ComponentClass<P> | React.StatelessComponent<P>;
type StateToProps = (setting: ApplicationState) => InjectedProps;
export function withUserSetting(
  stateToProps?: StateToProps
): <P extends InjectedProps>(WrappedComponent: ComponentType<P>) => void {
  return <P extends InjectedProps>(Comp: ComponentType<P>) => {
    class NewComponent extends (Component || PureComponent)<P> {
      render() {
        return <Comp {...this.props} />;
      }
    }
    return connect(stateToProps)(NewComponent as any);
  };
}

This HOC works fine and alerts me if the Props are missing because it expects the return type of 'InjectedProps':

https://i.stack.imgur.com/q5K4r.gif

However, I would like to modify the HOC so that it can alert me based on the return type of the 'stateToProps' function:

type AnyFunction = (...args: any[]) => any;
type ComponentType<P> = React.ComponentClass<P> | React.StatelessComponent<P>;
type StateToProps = (setting: ApplicationState) => { [key: string]: any };
export function withUserSetting<T extends AnyFunction>(
  stateToProps?: StateToProps
): <P extends ReturnType<T>>(WrappedComponent: ComponentType<P>) => void {
  return <P extends ReturnType<T>>(Comp: ComponentType<P>) => {
    class NewComponent extends (Component || PureComponent)<P> {
      render() {
        return <Comp {...this.props} />;
      }
    }
    return connect(stateToProps)(NewComponent as any);
  };
}

As you can see, the 'InjectedProps' is no longer required, allowing for flexibility in choosing prop names. Additionally, I am assuming that the 'ReturnType' decorator will automatically recognize the props and alert me if they are not declared for the component. However, it does not seem to have any effect:

https://i.stack.imgur.com/nAzb1.gif

The decorator itself works fine, but I am still missing the type safety that I desire. Do you have any ideas on why it is not working?

Answer №1

Having simplified and gained a better understanding of the code, I successfully achieved functionality. Here's the updated version:

type CustomType<P> = React.ComponentClass<P> | React.StatelessComponent<P>;
type MapToProps<T> = (settings: ApplicationState) => T;
export function incorporateUserSetting<T>(mapStateToProps?: MapToProps<T>):
  <P extends T>(WrappedComponent: CustomType<P>) => void {
  return <P extends T>(WrappedComponent: CustomType<P>) => {
    return connect(mapStateToProps)(WrappedComponent as any);
  };
}

Usage example:

@incorporateUserSetting((state) => ({ userId: state.userSetting.userId }))

Or like this:

@incorporateUserSetting<CustomProps>((state) => ({ userId: state.userSetting.userId }))

In both cases, an error will be raised if a property is absent in the declaration.

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

Connection error between frontend and backend was encountered

Whenever I try to register on my page and connect it to the database, I encounter an error after pressing the sign-in button... "Uncaught (in promise) TypeError: Converting circular structure to JSON --> starting at object with constructor &apo ...

Creating personalized themes in Material-UI

I am working on creating a unique theme and customizing various Material-UI components. Following the guidelines provided in this customization tutorial from Material-UI, I have made progress in the following areas: Creating a customized theme: //MUI THE ...

Can TypeScript automatically deduce keys from a changing object structure?

My goal here is to implement intellisense/autocomplete for an object created from an array, similar to an Action Creator for Redux. The array consists of strings (string[]) that can be transformed into an object with a specific shape { [string]: string }. ...

The Nextjs framework is experiencing a high total blocking time in its *****.js chunk

As I analyze the performance of next.js in my project, I am noticing a high total blocking time. Specifically, the "framework" chunk consistently takes more than 50ms. It seems that this chunk corresponds to the react and react-dom JavaScript files. Does ...

Updating the value of a different key within the same object using React Formik's setFieldValue方法

My objective is to automatically select a value in an option select when the onChange event occurs, and then use setFieldValue to set values for 2 Fields with key-value pairs within the same object. The issue I'm facing: Why does calling setFieldValu ...

Setting a value in Ionic 3 HTML template

Attempting to assign a value in an Ionic 3 template from the ts file while also adding css properties but encountered an issue. PROBLEM Error: Uncaught (in promise): Error: No value accessor for form control with name: 'image' Error: No va ...

Creating a Redis client in Typescript using the `redis.createClient()` function

I'm currently trying to integrate Redis (v4.0.1) into my Express server using TypeScript, but I've encountered a small issue. As I am still in the process of learning TypeScript, I keep getting red underline errors on the host parameter within th ...

Is it feasible to display Material components inside a material-table?

Currently, I am in the process of developing a data display feature for my application and have been exploring various data table components that are constructed using Material UI. One question that has arisen is whether it is feasible to incorporate Mater ...

ESLint and Prettier are butting heads when trying to run their commands consecutively

My package.json file includes two commands: "format": "prettier --write \"{src,{tests,mocks}}/**/*.{js,ts,vue}\"", "lint": "eslint . -c .eslintrc.js --rulesdir eslint-internal-rules/ --ext .ts,.js,.vue ...

Modifying the state object in ReactJS: A step-by-step guide on updating values

Below my query and explanation, you will find all the code. I am currently attempting to update the state in a grandparent class. This is necessary due to file-related reasons, and I am using Material-UI for text boxes. Additionally, I am implementing Red ...

Harnessing `prop` as a class identifier within the context of React and Material UI

I have a React component that needs to handle different status values such as "initialized", "connected", or "disconnected" through a 'status' prop. My goal is to dynamically apply a CSS class with the same name as the status value using materia ...

Are there any benefits to utilizing the Mantra.js architectural framework?

I have found that integrating Meteor.js into a Mantra.js architecture works seamlessly. However, I am questioning the advantages of using it since it seems to slow down the running of my requests. For example, when making a dummy request in GraphQL (such ...

NextJS is not displaying data fetched from getStaticProps on the page, although it is present in the props

I'm facing an issue with NextJS when trying to display text fetched from my API call. Essentially, I send an external HTTP request to retrieve some sample data. The data is returned as props for the component using the getStaticProps method. Within my ...

An error occurred with the datepicker: Unable to connect to 'bsValue' as it is not recognized as a property of 'input'

Despite importing DatepickerModule.forRoot() in my Angular unit test, I am encountering the following error: Error: Template parse errors: Can't bind to 'bsConfig' since it isn't a known property of 'input'. (" ...

VSCode displaying HTML errors within a .ts file

There is a strange issue with some of my .ts files showing errors that are typically found in HTML files. For example, I am seeing "Can't bind to 'ngClass' since it isn't a known property of 'div'" appearing over an import in ...

Managing Google OAuth using JWT in a react and Node.js environment

Currently, I am in the process of developing the authentication system for a web application. The client app is built using Next.js and the API is developed using Node.js. My Next.js app is running on port 3000 The API is externalized and running on port ...

Appending a new item to an array within a React useState object

As a JavaScript beginner, I am looking to add an element to an array within an object that is part of a react state. const [addVendor, setAddVendor] = React.useState({ vendorName: "", vendorPhone: "", vendorWhatsApp: " ...

Manipulate React class names by adding or removing them

Is there a way to toggle a className on click to change the style of a component? I need to rotate an arrow to the right when it's clicked and hide all components next to it using display: none;. I also require this functionality to work when ...

Utilizing 'nestjs/jwt' for generating tokens with a unique secret tailored to each individual user

I'm currently in the process of generating a user token based on the user's secret during login. However, instead of utilizing a secret from the environment variables, my goal is to use a secret that is associated with a user object stored within ...

Using the Upload feature in ReactJS

I have been searching high and low for assistance in creating a component within React that can handle file uploads to a specific endpoint I have established. I have experimented with various options, including trying to integrate filedropjs. However, I u ...