Search code examples
javascriptreactjstypescriptrecompose

Typescript, React and Recompose issues


Apologies in advance for the vague title it's quite hard to tl;dr my issue.

I'm trying to use the React, Recompose and Typescript together but when trying to pass props into my component I get the following error:

[ts] Property 'bar' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<{}, any, any>> & Readonly<{ children?: ReactNode; }> & Readonly<{}>'.

The component is imported like so:

import TestComponent from './TestComponent'

and called like so:

<TestComponent bar="hello"/>

Here is the structure of my component folder:

├── TestComponent.tsx
├── TestComponentContainer.ts
└── index.ts

index.ts is as follows:

import TestComponentContainer from './TestComponentContainer'

export default TestComponentContainer

TestComponent.jsx is as follows:

import * as React from 'react'

interface IProps {
  foo: string
  bar: string
}

const TestComponent: React.SFC<IProps> = ({ foo, bar }) => (
  <div>
    <p>{foo}</p>
    <p>{bar}</p>
  </div>
)

export default TestComponent

TestComponentContainer.ts is as follows:

import { compose, withProps } from 'recompose'

import TestComponent from './TestComponent'

export default compose(
  withProps({
    foo: 'stringy string string',
  }),
)(TestComponent)

I get that I'm missing some kind of type declaration for the props that are being passed through but can't for the life of me figure out exactly what I should do.

Edit:

Furthermore, how does one do this with the nested approach:

export default compose(
  setDisplayName('PlayerCardContainer'),
  withMutation(mutation),
  withHandlers(createHandlers),
)(PlayerCard)

Solution

  • The typing for compose is very generic and allows you to specify the type of the resulting component and the type of the component it can be called on but it doesn't ensure the type safety or compatibility of the functions handed to it.

    For this reason it is best to avoid compose and simply nest the HOC calls:

    import { withProps } from 'recompose';
    
    import TestComponent from './TestComponent';
    
    export default withProps({
      foo: 'stringy string string',
    })(TestComponent);
    

    Edit:

    For the added code example nesting the HOC's instead of using compose would look like this:

    export default setDisplayName('PlayerCardContainer')(
      withMutation(mutation)(
        withHandlers(createHandlers)(
          PlayerCard
        )
      )
    );