Skip to content

@types/react-redux The 'connect' function seems to be returning 'any' #37414

@josecarlosns

Description

@josecarlosns

If you know how to fix the issue, make a pull request instead.

If you do not mention the authors the issue will be ignored.

TL:DR

The connect function of react-redux is not returning a properly typed component, instead seems to be returning a any value, which breaks all the type-safety and intellisense of my Typescript code. Tested on @types/react-redux@^7.1.0.

Environmnent

react-native info:

System:
    OS: Linux 4.15 Linux Mint 19.1 (Tessa)
    CPU: (4) x64 Intel(R) Core(TM) i7-5500U CPU @ 2.40GHz
    Memory: 271.08 MB / 7.71 GB
    Shell: 4.4.20 - /bin/bash
  Binaries:
    Node: 12.4.0 - ~/.nvm/versions/node/v12.4.0/bin/node
    Yarn: 1.17.3 - ~/.nvm/versions/node/v12.4.0/bin/yarn
    npm: 6.9.0 - ~/.nvm/versions/node/v12.4.0/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  npmPackages:
    react: 16.8.6 => 16.8.6 
    react-native: ^0.60.4 => 0.60.4 
  npmGlobalPackages:
    react-native-cli: 2.0.1

package.json: (I've ommited some unrelated dependencies for the sake of simplicity)

"dependencies": {
    "react": "16.8.6",
    "react-native": "^0.60.4",
    "react-redux": "^7.1.0",
    "redux": "^4.0.4",
    "redux-thunk": "^2.3.0",
  },
  "devDependencies": {
    "@types/react": "^16.8.23",
    "@types/react-native": "^0.60.1",
    "@types/react-redux": "^7.1.0",
    "@types/redux-thunk": "^2.1.0",
    "typescript": "^3.5.3"
  }

Context

So I'm working on a React-native project on my job and I decided to use Typescript for type-safety and autocomplete/intellisense features on my IDE of choice (Visual Studio Code). Also keep in mind that I'm relatively new to Typescript, so I may be doing something wrong, if thats the case please correct me.

So to use typescript with react-native I would define a component like this:

interface Props {
  label: string;
}

class CustomComponent extends Component<Props> {
  render(): ReactElement {
    return (
      <View>
        <Text>{this.props.label}</Text>
      </View>
    );
  }
}

export default CustomComponent;

And I would get the expected behavior, that is proper type-checking and autocompletion features on VS Code:

image

That error on the component its because its lacking the label prop, that I defined in the component's Props interface, and since I didn't define any defaultProps or marked it with the optional flag (?) it makes it a required prop.

But lets say I want to connect that component to my Redux Store, then I would use the connect function of react-redux and map props and/or action creators to it, like this:

// Properties passed from the parent component
interface OwnProps {
  label: string;
}

// Properties passed from the store
interface StoreProps {
  theme: 'light' | 'dark';
}

// Props of the component
type Props = OwnProps & StoreProps;

class CustomComponent extends Component<Props> {
  render(): ReactElement {
    return (
      <View>
        <Text
          style={{ color: this.props.theme === 'light' ? 'white' : 'black' }}
        >
          {this.props.label}
        </Text>
      </View>
    );
  }
}

// The store structure, defined here for the sake of simplicity
interface Store {
  theme: 'light' | 'dark';
}

const mapStateToProps = (state: Store): StoreProps => {
  const { theme } = state;

  return {
    theme
  };
};

export default connect(mapStateToProps)(
  CustomComponent
);

But when I do this the component loses all type-safety and autocompletion, where it basically accepts any prop with any value, and the IDE doesn't detect its possible props:

image

The code works as expected, but it loses all features that made me use typescript in the first place, so thats a no no.

After searching basically everywhere on the interwebs and asking on 2 slack channels and a discord server, I couldn't find an answer for this riddle. But I found something: it seems that the connect function, even with proper generic type arguments, is returning a any value and, obviously, thats not a properly typed React component!

image

So what am I doing wrong? I've been through basically dozens of articles and guidelines about how to properly type redux-connected components, and it just doesn't work, and I kinda need this to work, because deadlines. Please help, send the eagles.

Workaround

Just manually type the default export, like this:

const connectedComponent: typeof CustomComponent = connect<
  StoreProps,
  DispatchProps,
  OwnProps,
  Store
>(mapStateToProps)(CustomComponent);

export default connectedComponent;

With that typescript works as expected with type-checking and intellisense, but still thats just a workaround and may cause unexpected behavior down the line.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions