Type '{}' is missing the following properties from type

Viewed 1771

In my React project I am getting the following error for my App component.

Type '{}' is missing the following properties from type 'Pick<ClassAttributes<App> & RouteChildrenProps<{}, unknown> & { userData: UserDataType | undefined; userRightList: UserRightListType[] | undefined; userPermissionList: string[] | undefined; } & { ...; }, "ref" | ... 3 more ... | "key">': history, location, matchts(2739)

Following is my index.tsx file code:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import App from './App';
import reportWebVitals from './reportWebVitals';
import reduxStore from './redux/store';

ReactDOM.render(
  <Provider store={reduxStore.store}>
    <BrowserRouter>
      <App /> // getting the error here
    </BrowserRouter>
  </Provider>,
  document.getElementById('root')
);

reportWebVitals();

and following is my App.tsx file code:

import { Component, Fragment } from 'react';
import { connect } from 'react-redux';
import { RouteComponentProps } from 'react-router-dom';
import ErrorBoundary from './components/ErrorBoundary';
import { getUserByToken, getUserRights, setUserRights } from './redux/actions';
import { ReduxStateType } from './type-definitions';
import { isAuthenticated } from './utils/is-authenticated';

type StoreProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatch;

type PropsType = RouteComponentProps & StoreProps & DispatchProps;

class App extends Component<PropsType, any> {
  componentDidMount() {
    const {
      userData,
      getUserByToken,
      getUserRights,
      userRightList,
    } = this.props;
    const isAuth = isAuthenticated(userData);
    if (!userData?.username && isAuth) {
      getUserByToken();
    }
    if (userRightList?.length === 0 && isAuth) {
      getUserRights();
    }
  }

  componentDidUpdate(prevProps: PropsType) {
    const {
      userData,
      userRightList,
      userPermissionList,
      setUserRights,
    } = this.props;

    if (
      userData &&
      Object.keys(userData).length > 0 &&
      userRightList &&
      userRightList?.length > 0 &&
      userPermissionList?.length === 0
    ) {
      setUserRights();
    }
  }

  render() {
    return (
      <Fragment>
        <ErrorBoundary></ErrorBoundary>
      </Fragment>
    );
  }
}

function mapStateToProps(state: ReduxStateType) {
  return {
    userData: state.auth?.userData,
    userRightList: state.auth?.userRightList,
    userPermissionList: state.shared?.userPermissionList,
  };
}

const mapDispatch = {
  getUserByToken,
  getUserRights,
  setUserRights,
};

export default connect<StoreProps, DispatchProps>(
  mapStateToProps,
  mapDispatch
)(App);

I am getting the error in index.tsx file in the render method. I am new to TypeScript. I would appreciate it very much if someone can tell me where I am doing wrong.

1 Answers

You have two different packages which might be injecting their own props into your component: Redux and React Router.

When you define your component as class App extends Component<PropsType, any>, it expects to receive PropsType as its props.

type PropsType = RouteComponentProps & StoreProps & DispatchProps;

It needs to receive all three of the interfaces that you've listed as props. StoreProps and DispatchProps are the ones which are injected by the Redux connect higher-order component, and these ones are fine. Your error message tells you that the missing props are history, location, and match. These are the properties of RouteComponentProps.

Right now your component doesn't actually use any of the Router props, so the simplest solution is just to remove RouteComponentProps from PropsType. By putting it there, you are requiring that those props be present.

If you want to actually include the RouteComponentProps, then changes need to be made in index.tsx. You have wrapped your App in a BrowserRouter, but it's not actually doing anything because you haven't defined any routes. You need a Switch component with Route components inside of it. If App is loaded within a Route component, then the RouteComponentProps will be injected.

Check out the React Router docs for how to set up multiple routes. This will load App always (so no change), but now it will get the required props. There are multiple ways to declare the component for a Route, but you want to use the component prop or render prop instead of children because these allow typescript to know that the router props are included.

ReactDOM.render(
  <Provider store={reduxStore.store}>
    <BrowserRouter>
      <Switch>
        <Route
          path="/"
          component={App}
        />
      </Switch>
    </BrowserRouter>
  </Provider>,
  document.getElementById('root')
);
Related