0
votes

In my Route component i have a Layout HOC that have some components as Children. In this HOC, i render the Top and Side bars, and i also connect him to my redux store to get the current user and dispatch the logout action. The problem is i defined my Hoc's Props and put the children as ReactNode, my user as UserType and the logout action as a function. But in the Route component i get a error because a didn't pass the user and the action as props.

My HOC component

interface Props extends RouteComponentProps {
  children?: ReactNode
  user?: UserType
  logoutAction(): void
}

const AppLayout = (props: Props) => (
  <Layout>
    {/* <Sidebar {...props} /> */}
    <Layout>
      {/* <TopBar user={props.user} /> */}
      <Content
        style={{
          margin: '24px 16px',
          padding: 24,
          background: '#fff',
          minHeight: 280
        }}
      >
        {props.children}
      </Content>
    </Layout>
  </Layout>
)
const mapStateToProps = (state: AppStateType, ownProps: Props) => ({
  ...ownProps,
  user: state.auth.currentUser
})

const mapDispatchToProps = (dispatch: Dispatch) => ({
  logoutAction: () => dispatch(logoutUserSuccessAction())
})

export default withRouter(
  connect(
    mapStateToProps,
    mapDispatchToProps
  )(AppLayout)
)

My Route Component

class Routes extends React.Component<Props> {
  componentDidMount = () => {
    this.props.fetchFields()
    // this.props.fetchQuestions();
  }

  render() {
    return (
      <div
        style={{
          display: 'flex',
          height: '100vh',
          flexDirection: 'column',
          width: '100vw'
        }}
      >
        <AppLayoutContainer>
          <React.Fragment>
            <Switch>
              <Route path="/" exact component={HomePageContainer} />

              <Route path="/login" exact component={LoginPageContainer} />
              {/* NEED AUTH HOC */}
              <Route path="/gerencia" component={GerenciaPageContainer} />
              <Route path="/relatorio" component={ReportPageContainer} />
              <Route path="/exportar" component={ExportPageContainer} />
            </Switch>
          </React.Fragment>
        </AppLayoutContainer>
      </div>
    )
  }
}

The error i got:

Property 'logoutAction' is missing in type '{ children: Element; }' but required in type 'Readonly<Pick<Pick<Props, never> & Props, "user" | "children" | "logoutAction">>'.ts(2741)
AppLayoutContainer.tsx(20, 3): 'logoutAction' is declared here.

I'm trying to type the connect function but i'm getting other error:

interface OwnProps extends RouteComponentProps {
  children?: ReactNode
  // user?: UserType
}

interface StateProps {
  user?: UserType
}

interface DispatchProps {
  logoutAction: () => void
}

type Props = StateProps & DispatchProps & OwnProps

const AppLayout = (props: Props) => (
  <Layout>
    {/* <Sidebar {...props} /> */}
    <Layout>
      {/* <TopBar {...props} /> */}
      <Content
        style={{
          margin: '24px 16px',
          padding: 24,
          background: '#fff',
          minHeight: 280
        }}
      >
        <Button onClick={() => props.logoutAction()}>Fazer Logout</Button>
        {props.children}
      </Content>
    </Layout>
  </Layout>
)

function mapStateToProps(
  state: AppStateType,
  ownProps: OwnProps
): StateProps & OwnProps {
  // ...ownProps,
  return {
    ...ownProps,
    user: state.auth.currentUser
  }
}

const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
  logoutAction: () => dispatch(logoutUserSuccessAction())
})

export default connect<StateProps, DispatchProps, void>(
  mapStateToProps,
  mapDispatchToProps
)(AppLayout)

and i'm getting this error now:

Argument of type '(state: { auth: AuthReducerStateType; }, ownProps: OwnProps) => StateProps & OwnProps' is not assignable to parameter of type 'MapStateToPropsParam<StateProps, void, {}>'.
  Type '(state: { auth: AuthReducerStateType; }, ownProps: OwnProps) => StateProps & OwnProps' is not assignable to type 'MapStateToPropsFactory<StateProps, void, {}>'.
    Types of parameters 'state' and 'initialState' are incompatible.
      Property 'auth' is missing in type '{}' but required in type '{ auth: AuthReducerStateType; }'.ts(2345)
getReducers.ts(41, 3): 'auth' is declared here.
1

1 Answers

1
votes

So logoutAction is provided by redux, not manually by you.

You've marked this prop as required. Typescript doesnt know it's redux component and it'll have this prop passed basing on mapDispatchToProps so it's complaining you didn't provide it

In such case, when some prop is provided by external lib (redux in your case) I usually mark it as optional (which makes sense because you don't really control this prop being passed)

interface Props extends RouteComponentProps {
  children?: ReactNode
  user?: UserType
  logoutAction()?: void // <<<--- ? added
}

Should solve the issue