Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Recompose Causing Typescript Error On Props

I have a very basic stateful component where I'm using recompose to add multiple HOC to my component (in my example I only use one for simplicity). For some reason typescript is giving me an error regarding my props going into my component. How can I get rid of this error?

Here's my code:

import * as React from 'react';
import { connect } from 'react-redux';
import { compose } from 'recompose';

interface IStoreState {
  readonly sessionState: {
    authUser: { email: string; }
  }
}

interface IAccountPageProps { 
  authUser: { email: string } 
}

const AccountPage = ({ authUser }: IAccountPageProps ) =>
    <div>
      <h1>Account: {authUser.email}</h1>
    </div>

const mapStateToProps = (state: IStoreState) => ({
  authUser: state.sessionState.authUser,
});

export default compose(
  connect(mapStateToProps)
)(AccountPage);

And the error I'm getting is:

Argument of type '({ authUser }: IAccountPageProps) => Element' is not assignable to parameter of type 'ComponentType<{}>'.
  Type '({ authUser }: IAccountPageProps) => Element' is not assignable to type 'StatelessComponent<{}>'.
    Types of parameters '__0' and 'props' are incompatible.
      Type '{ children?: ReactNode; }' is not assignable to type 'IAccountPageProps'.
        Property 'authUser' is missing in type '{ children?: ReactNode; }'.

If I don't use recompose and instead write

export default connect(mapStateToProps)(AccountPage)

I do not get any errors.

like image 607
Jon Lamb Avatar asked Jul 31 '18 03:07

Jon Lamb


2 Answers

The current typing of compose is pretty useless. If you want to use compose, you have to specify the props type of the original and final components manually, and there is no checking that the types you specified match the list of higher-order components you passed:

export default compose<IAccountPageProps, {}>(
  connect(mapStateToProps)
)(AccountPage);

I'd recommend not using compose in TypeScript.

like image 88
Matt McCutchen Avatar answered Nov 15 '22 14:11

Matt McCutchen


The typing for compose allows you to specify the type of the resulting component and the type of the component it can be called on, so this will avoid the errors:

export default compose<IAccountPageProps, {}>(
  connect(mapStateToProps)
)(AccountPage);

Unfortunately, compose does nothing to ensure the type safety or compatibility of the functions handed to it.

So, for example, this won't generate a typing error even though it is obviously invalid:

export default compose<IAccountPageProps, {}>(
  connect(mapStateToProps),
  () => 'compose typing allows any function'
)(AccountPage);

It is safer to nest the HOC calls:

export default 
connect(mapStateToProps)(
  firstHoc(
    secondHoc(
      AccountPage
    )
  )
);
like image 5
Brian Adams Avatar answered Nov 15 '22 15:11

Brian Adams