8
votes

In case compose is used there is an error JSX element type ‘Option’ does not have any construct or call signatures. 'redux' version - 3.7.2

import * as React from 'react';
import { compose } from 'redux';
import { connect } from 'react-redux';
const { connect: fela, withTheme } = require('react-fela');

const Option = compose(
    ...[
        connect(null,
            dispatch => ({
                onClick: (name) => dispatch(setActive(name)),
            })),
        fela({
            option: ({ theme }) => ({
                ...getControlOptionColors(theme),
            }),
        }),
    ],
)(withTheme(({ label, name, onClick, styles }) => (
    <div className={styles.option} onClick={onClick.bind(this, name)}>{label}</div>
)));

export class Test extends React.PureComponent<any, any> {

    private renderOptions(options) {
        return (
            <div className={this.props.styles.options}>
                {options.map(option => (
                    <div key={option.value}>
                        <Option
                            label={option.label}
                            name={option.value}
                        />
                    </div>
                ))}
            </div>
        );
    }


    public render() {
        const { options } = this.props;
        return (
            <div className={this.props.styles.container}>
                {this.renderOptions(options)}
            </div>
        );
    }
}

export default Controls;

Without compose, Everything work fine.

const Element = withTheme(({ label, name, onClick, styles }) => (
        <div className={styles.option} onClick={onClick.bind(this, name)}>{label}</div>
    ))

const conponentWithConnect = connect(null,
    dispatch => ({
        onClick: (name) => dispatch(setActive(name)),
    }))(Element);

const Option = fela({
        option: ({ theme }) => ({
                    ...getControlOptionColors(theme),
        }),
    })(withConnect)
3
Looks like there is an issue with the redux types - marvinhagemeister

3 Answers

23
votes

You need to type cast the component returned by compose as React.ComponentType and it works fine. So:

compose(...)(SomeComponent) as React.ComponentType
6
votes

An updated answer; use the generics for compose:

import React, { ComponentType, FC } from 'react';

export default compose<ComponentType>(
  withWidth,
  connect(
    mapStateToProps,
    mapDispatchToProps
  )
)(Search)
0
votes

The problem is probably that you are wrapping your arguments to compose in an array, and then destructuring the array using the spread operator (...).

There is no reason to do this since it is semantically equivalent to passing the arguments directly. This construction may also prevent TypeScript from inferring the type parameters for compose correctly.

You could rewrite your compose call as

const Option = compose(
    connect(null,
        dispatch => ({
            onClick: (name) => dispatch(setActive(name)),
        })),
    fela({
        option: ({ theme }) => ({
            ...getControlOptionColors(theme),
        }),
    }),
)(withTheme(({ label, name, onClick, styles }) => (
    <div className={styles.option} onClick={onClick.bind(this, name)}>{label}</div>
)));

That might solve the problem, but I can’t be sure as the snippet of code you’ve provided is not sufficiently complete for me to test it.