React-redux-firebase: bug(typings): issues with firebaseConnect & withFirebase in Typescript

Created on 30 Oct 2017  路  14Comments  路  Source: prescottprue/react-redux-firebase

I'm running into problems connecting my component when using Typescript.

export default compose(
  firebaseConnect(),
  connect(({ firebase: { auth } }) => ({ auth }))
)(LoginPage);

error TS2604: JSX element type 'LoginPage' does not have any construct or call signatures.

The TS compiler is fine if I leave out the react-redux-firebase connector:

export default compose(
  connect(({ firebase: { auth } }) => ({ auth }))
)(LoginPage);

Also this syntax seems to work, manually passing the output from one function into the other.

export default connect(({ firebase: { auth } }) => ({ auth }))(
  firebaseConnect()(LoginPage)
);

And as I understand it withFirebase could be used in place of firebaseConnect() (no arguments), but if I do that I get a different error.

export default connect(({ firebase: { auth } }) => ({ auth }))(
  withFirebase(LoginPage)
);

Results in:

Warning: Failed child context type: Cannot read property 'store' of undefined in withContext(getContext(withProps(LoginPage))) (created by Connect(withContext(getContext(withProps(LoginPage))))) in Connect(withContext(getContext(withProps(LoginPage)))) (created by App)

bug

Most helpful comment

BTW as you see there is also some old login code I used to implement auth with firebaseui. Please ignore that.

Meanwhile I found a workaround to easily circumvent the TS compiler error:

export default compose(
  firebaseConnect(),
  connect(({ firebase: { auth } }) => ({ auth }))
)(PrivateRoute) as any;

All 14 comments

@0x80 First: which version are you running? There have been releases in the last few days that may fix what you are seeing with withFirebase).

Second: It would be awesome to see a typescript example I could test things out it within. Since I don't often use it, I don't have a regular typescript setup/project to test things in.

I'm using beta.14. I'll try to prepare a repo for you. I don't have time to set something up from scratch, and the project is not OSS, so I'll have to strip out some things first.

BTW as you see there is also some old login code I used to implement auth with firebaseui. Please ignore that.

Meanwhile I found a workaround to easily circumvent the TS compiler error:

export default compose(
  firebaseConnect(),
  connect(({ firebase: { auth } }) => ({ auth }))
)(PrivateRoute) as any;

@0x80 It is definitely helpful to know the workaround.

I had the same problem and this helped me:
https://spin.atomicobject.com/2017/04/20/typesafe-container-components/

I ended up using this:

interface StateFromProps {
    auth: any | null;
}

export default connect<StateFromProps, {}, void>(
    (state: any) => ({
        auth: state.firebase.auth
}))(firestoreConnect()(App));

@Klabauterman Very helpful! Thanks for sharing the article!

It might be good to add a typescript example incase people run into this in the future (would also be helpful for future development of typings).

Are there any changes that should be made to the typings for firebaseConnect based on this or should we close?

I feel the generated types file from dts-gen is messy and largely incorrect, but I don't know enough about Typescript or your library to offer to take this on.

@Klabauterman If I have a component that needs both firebase state from redux and the firebase instance to call methods on, would the code below be correct?

interface StateFromProps {
  auth: any | null;
}

interface PropsFromProps {
  firebase: any | null;
}

export default compose(
  firebaseConnect(),
  connect<StateFromProps, PropsFromProps, void>((state: any) => ({
    auth: state.firebase.auth,
  }))
)(Login);

I'm not happy with the name PropsFromProps, but I'm also unsure why you called the other one StateFromProps. Could it be StoreToProps or StateToProps, since it's a mapping?

Never mind! I think I was trying to fix an error that I didn't understand. Of course the second parameter to connect is mapDispatchToProps, and has nothing to do with this.

But the StateFromProps question still stands. I think PropsFromState makes a lot more sense. Because you're converting redux state to component props. What do you think?

Sorry for the noise. I clicked close by accident. Then opened it, and noticed it was moved to done. Closed it again.... I don't know. I think this is not an issue anymore.

As long as you don't try to use redux compose with firebaseConnect you're fine. I'm not sure if the problem is with my use of compose, or with the firebaseConnect type signature...

But I'll let you decide so I'll open it again 馃槃

Ah yes, I still have an issue with this.

For example the code below compiles without errors, but if I try to use the component in JSX I do not get any warning about missing props. This is because the firebase/firestoreConnect() return type is any.

@Klabauterman any idea how I can make the JSX aware of the required props?

import * as React from 'react';
import { firestoreConnect } from 'react-redux-firebase';
import { Card } from 'antd';
import Form from './confirm-user-profile-form';
import notify from 'helpers/notify';
import createCommand from 'helpers/create-command';
import { UserProfile } from 'types';

import { compose, withHandlers } from 'recompose';

interface ConfirmUserProfileProps {
  firestore: any;
  userProfile: UserProfile;
  onSubmit: (payload: any) => Promise<void>;
}

const ConfirmUserProfile: React.SFC<ConfirmUserProfileProps> = ({
  userProfile,
  onSubmit,
}) => {
  return (
    <Card title="Confirm User Profile" style={{ maxWidth: 600 }}>
      <Form userProfile={userProfile} onSubmit={onSubmit} />
    </Card>
  );
};

const onSubmit = props => async payload => {
  try {
    const { firestore, userProfile: { userId } } = props;
    const command = createCommand('confirmUserProfile', firestore, userId);

    await command(payload);

    notify.success({
      message: `Confirmed user profile`,
    });
  } catch (err) {
    notify.error(err);
  }
};

const enhance = compose(
  withHandlers({
    onSubmit,
  })
);

export default firestoreConnect()(enhance(ConfirmUserProfile));

The v2.0.0-rc.1 release includes a switch to creating all HOCs within react-redux-firebase instead of using recompose's withContext and getContext (recompose is not longer a dependency).

It seems like the theory of these recompose HOCs being the issue was correct since I was no longer having the issue when running with react 16.

If you are still seeing this after upgrading, reach out.

Was this page helpful?
0 / 5 - 0 ratings