Definitelytyped: [@types/react-redux v7.1.4] Problem parsing props on JS components that use react-redux from TS components.

Created on 27 Sep 2019  Â·  24Comments  Â·  Source: DefinitelyTyped/DefinitelyTyped

Hi, After the MR https://github.com/DefinitelyTyped/DefinitelyTyped/pull/38179 author @OliverJAsh. On my project I'm having a few problems with some tsx file that have reference to components that are using Proptypes with connect of react-redux on JS. I have narrow it down to this change since v7.1.3 is working fine.

On all those cases I'm getting the same error, for example:
Type '{ propName: ReactNode; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Pick<RouteComponentProps<any, StaticContext, any>, never>, any, any>> & Readonly<Pick<RouteComponentProps<any, StaticContext, any>, never>> & Readonly<...>'. Property 'propName' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Pick<RouteComponentProps<any, StaticContext, any>, never>, any, any>> & Readonly<Pick<RouteComponentProps<any, StaticContext, any>, never>> & Readonly<...>'. TS2322

https://github.com/Nicolas-Vega/TestTSReactRedux

Example of this:
Detail.tsx:

import React from "react";
import Header from "./Header";

type Props = {
  propName?: React.ReactNode;
};

class Detail extends React.PureComponent<Props> {
  render() {
    const {
      propName
    } = this.props;
    return (
      <>
        <Header backButton={propName} />
      </>
    );
  }
}

export default Detail;

Header.js:

import React from "react";
import PropTypes from "prop-types";
import { conneimport React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";

class Header extends React.PureComponent {

  render () {
    return (<>Test</>);
  };
}

Header.propTypes = {
  backButton: PropTypes.any,
};

export default withRouter(
  connect(
    state => ({
      user: state,
    }),
    {}
  )(Header)
);

_Originally posted by @Nicolas-Vega in https://github.com/DefinitelyTyped/DefinitelyTyped/pull/38179#issuecomment-536088368_

Most helpful comment

I'm getting the same error, but with children instead of propName:

CustomProvider:

const CustomProvider: FunctionComponent<Props> = props => (
  <MuiThemeProvider theme={getThemeFromThemeId(props, props.theme)}>
    {props.children}
  </MuiThemeProvider>
);

const mapStateToProps = (state: State, ownProps: OwnProps) => ({
  theme: getCurrentThemeId(ownProps.allowTheme)(state),
});

export default connect(mapStateToProps)(CustomProvider);

app.tsx:

ReactDOM.render(
  <StylesProvider>
    <Provider store={reduxStore}>
      <CustomProvider darkTheme={darkTheme} lightTheme={lightTheme}>
        <RootComponent />
      </CustomProvider >
    </Provider>
  </StylesProvider>,
  document.querySelector('.root-anchor')
);

Error:

ERROR in C:/projects/paragoncore-hr0q3/clients/design-client/source/scripts/components/app.tsx
ERROR in C:/projects/paragoncore-hr0q3/clients/design-client/source/scripts/components/app.tsx(42,8):
TS2322: Type '{ children: ReactNode; darkTheme: Theme; lightTheme: Theme; }' is not assignable to type 'IntrinsicAttributes & Pick<Props, "darkTheme" | "lightTheme"> & OwnProps'.
  Property 'children' does not exist on type 'IntrinsicAttributes & Pick<Props, "darkTheme" | "lightTheme"> & OwnProps'.

All 24 comments

What line are you getting this error on? It seems odd to me because the react-redux part has nothing to do with a Type '{ propName: ReactNode; }' -- you extract propName before entering any react-redux-wrapped components.

I thought the same, It took me a long time to narrow it to this change since I thought it was related to other @types. On my example If I call the Header component like this:

<Header />

It didn't give me any error. I have tried also to change the props-types of the JS to match it exactly and seems that Typescript if you are using connect don't parse the props of the JS. Maybe on the MR there is something that prevent Typescript to reach the component props or something like that.

On my project at the end I just changed the package.json to force it the version 7.1.3 instead of ^7.0.0 and it fixed all the issues I was having.

"@types/react-redux": "7.1.3",

I'm getting the same error, but with children instead of propName:

CustomProvider:

const CustomProvider: FunctionComponent<Props> = props => (
  <MuiThemeProvider theme={getThemeFromThemeId(props, props.theme)}>
    {props.children}
  </MuiThemeProvider>
);

const mapStateToProps = (state: State, ownProps: OwnProps) => ({
  theme: getCurrentThemeId(ownProps.allowTheme)(state),
});

export default connect(mapStateToProps)(CustomProvider);

app.tsx:

ReactDOM.render(
  <StylesProvider>
    <Provider store={reduxStore}>
      <CustomProvider darkTheme={darkTheme} lightTheme={lightTheme}>
        <RootComponent />
      </CustomProvider >
    </Provider>
  </StylesProvider>,
  document.querySelector('.root-anchor')
);

Error:

ERROR in C:/projects/paragoncore-hr0q3/clients/design-client/source/scripts/components/app.tsx
ERROR in C:/projects/paragoncore-hr0q3/clients/design-client/source/scripts/components/app.tsx(42,8):
TS2322: Type '{ children: ReactNode; darkTheme: Theme; lightTheme: Theme; }' is not assignable to type 'IntrinsicAttributes & Pick<Props, "darkTheme" | "lightTheme"> & OwnProps'.
  Property 'children' does not exist on type 'IntrinsicAttributes & Pick<Props, "darkTheme" | "lightTheme"> & OwnProps'.

I'm getting the same error, but with children instead of propName:

Hi @Methuselah96 are you having this issue with the last version of @types/react-redux? Have you tried to downgrade to v7.1.3? If it does fix your issue let us know.

This issue that I have reported it only appears on v7.1.4 of @types/react-redux.

In your example it seems that CustomProvider don't have declared childens on his prop declaration.

I'm getting the same error, but with children instead of propName:

Hi @Methuselah96 are you having this issue with the last version of @types/react-redux? Have you tried to downgrade to v7.1.3? If it does fix your issue let us know.

I have this error (Property 'children' does not exist...) with 7.1.4 only. 7.1.3 works fine.

I'm on holiday until 7th October, so I can't take a look until then at the
earliest.

Re. children, I suspect this is because children is intentionally omitted
from the component type now–the maintainers for these typings want users to
define it manually. I can link to another thread explaining that once I am
home and on my laptop.

On Mon, 30 Sep 2019, 18:32 Mike Aizatsky, notifications@github.com wrote:

I'm getting the same error, but with children instead of propName:

Hi @Methuselah96 https://github.com/Methuselah96 are you having this
issue with the last version of @types/react-redux? Have you tried to
downgrade to v7.1.3? If it does fix your issue let us know.

I have this error (Property 'children' does not exist...) with 7.1.4 only.
7.1.3 works fine.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/38678?email_source=notifications&email_token=AAHBACLQPJPMHXNPLMOHYITQMIZ2NA5CNFSM4I3KXQNKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD76OBIQ#issuecomment-536666274,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAHBACONBGVR64M7JQ7MWS3QMIZ2NANCNFSM4I3KXQNA
.

@Nicolas-Vega Yes, this is an issue only with 7.1.4. 7.1.3 does not produce an error for me.

@OliverJAsh Yeah, it'd be nice to see a thread explaining that. Are they requiring it be manually defined for NamedExoticComponent, but not ComponentClass? That would seem inconsistent to me.

IIRC they didn't want to make a breaking change, so for now it's only
applied to new component types. I'll link you up when I can

On Mon, 30 Sep 2019, 19:17 Nathan Bierema, notifications@github.com wrote:

@Nicolas-Vega https://github.com/Nicolas-Vega Yes, this is an issue
only with 7.1.4. 7.1.3 does not produce an error for me.

@OliverJAsh https://github.com/OliverJAsh Yeah, it'd be nice to see a
thread explaining that. Are they requiring it be manually defined for
NamedExoticComponent, but not ComponentClass? That would seem
inconsistent to me.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/38678?email_source=notifications&email_token=AAHBACIEEUDQLFIJ5VGCZZDQMI7FNA5CNFSM4I3KXQNKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD76S26A#issuecomment-536685944,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAHBACPPESEENE2WBYZAEKDQMI7FNANCNFSM4I3KXQNA
.

This actually breaks a lot, since any React.FC has its props intrinsically decorated with PropsWithChildren, which is not the case with ExoticComponent.

Also the react typings file explicitly state in regards to ExoticComponent.

We don't just use ComponentType or SFC types because you are not supposed to attach statics to this object, but rather to the original function.

If I get it right this breaks commutative property of operations when applying both React.memo and connect to the same component

children is intentionally omitted from the component type now–the maintainers for these typings want users to define it manually

Explanation: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/33602#issuecomment-470143143

/cc @Methuselah96

@Nicolas-Vega I am able to reproduce your issue (with the exact code provided) on @types/react-redux 7.1.3, which was before https://github.com/DefinitelyTyped/DefinitelyTyped/pull/38179. I'm using TS 3.6.3. Note your code had some syntax errors which I had to fix.

Please can you provide a full reduced test case in the form of a repository, with package.json, tsconfig.json, etc?

Regarding the other issue with children, that is working as intended. See https://github.com/DefinitelyTyped/DefinitelyTyped/issues/38678#issuecomment-539534741.

Hi @OliverJAsh , here is a project with the full test case. I left "@types/react-redux" @7.1.3 , to get the error you have to change it to 7.1.4 and then run again yarn or npm or what you use.

https://github.com/Nicolas-Vega/TestTSReactRedux

This is the error you should get:
error

Hope this help! Let me know if you need anything else.

Thanks!

So it looks like the problem is with withRouter:

import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { withRouter } from "react-router-dom";

class Header extends React.Component {
  static propTypes = {
    backButton: PropTypes.number
  };
}

<Header backButton={1} />; // works

const HeaderConnected = connect()(Header);

<HeaderConnected backButton={1} />; // works

const HeaderConnectedWithRouter = withRouter(HeaderConnected);

<HeaderConnectedWithRouter backButton={1} />; // error!

I'll try to investigate more tomorrow, but I'm confident the type change I made to react-redux is correct—something else probably needs to change.

In a .ts/.tsx file, the following code errors. Note how this has nothing to do with react-redux:

import React from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router-dom";

class Header extends React.Component {
  static propTypes = {
    backButton: PropTypes.number
  };
}

const HeaderWithRouter = withRouter(Header); // error

In your example repo, if you rename your Header.js to Header.tsx, you will receive the same error when using @types/[email protected]

This error is because Header must be typed to receive RouteComponentProps.

(Why don't we see this error when using @types/[email protected]? I don't fully understand that, but I suspect the error is just being pushed further downstream.)

(Note: in a .js file, propTypes does not seem to infer the TS prop types (unlike in a .ts/.tsx file). Your example code was not type safe—although there were no errors when using @types/[email protected], it was possible to pass any props into Header.)

We can annotate the component with our own props and RouteComponentProps using JSDoc (or rename to .tsx and use TS syntax). When we do this, your error disappears.

 import React from "react";
 import PropTypes from "prop-types";
 import { withRouter } from "react-router";
 import { connect } from "react-redux";
 import { RouteComponentProps } from "react-router-dom";

+/** @extends {React.Component<{ backButton?: number } & RouteComponentProps>} */
 class Header extends React.Component {
   static propTypes = {
     backButton: PropTypes.number
   };
 }

 export default withRouter(connect()(Header));

Unfortunately I don't have anymore time to look into this, but I'm convinced the problem is not with react-redux or the change I made recently. It has just helped to uncover other problems in your code and maybe the types for react-router.

Well in my project I have a lot of components that are still in JS and they work together with other components wrote in TS. Currently we don't plan to transfer to TS or strongly type them since its a lot of work. Also typing components is not a solution, nobody that is migrating a full JS project to TS will type all his components on the first try. TS and JS component should work alongside with no problem...

I propose since this change break compatibility in some cases that change the version 7.1.4 to 8.0.0 for example. With that at least anyone that download the new version would at least expect some breaking changes.

Tag some other contributors so they can check this.
@uniqueiniquity @soerenbf

@OliverJAsh regarding issue with children: as far as I understand react typings still inject children prop to class-based or functional component typings. In other words it still allows to pass children to components that have no explicit children in their props typings. Why does a connected version require children to be explicitly specified? Here is an example to illustrate what I'm talking about.

As @octaharon pointed out, it breaks a lot. In our project I've got 130+ type errors after updating to the latest react-redux typings version.

@sergey-be

  1. Since react-redux v7.0.1, connect now uses React.memo (see release notes). This means connect now returns a type of NamedExoticComponent, because this is what React.memo returns. The types were updated to reflect this in https://github.com/DefinitelyTyped/DefinitelyTyped/pull/38179.
  2. The maintainers of the React typings have decided to deliberately omit children from all new component types (such as the one returned by React.memo and the one used here). This change hasn't been made to old component types (e.g. Component and FunctionComponent) as it would be a breaking change.
  3. Going forward, it is encouraged that users manually add a childrenprop to all of their components—but right now it is only required for NamedExoticComponent.

If you're not happy with the decision of the React type maintainers to omit children from NamedExoticComponent, I would suggest focusing your efforts beside this comment.

What do you think about this case:

function A({ prop }: { prop?: string }) {
    return <div>{prop}</div>;
}

function B({ Comp }: { Comp: React.ComponentType }) {
    return <Comp />;
}

connect(() => ({
    Comp: connect(() => ({}))(A),
}))(B);
Argument of type '({ Comp }: { Comp: ComponentType<{}>; }) => Element' is not assignable to parameter of type 'ComponentType<Matching<{ Comp: ConnectedComponent<({ prop }: { prop?: string | undefined; }) => Element, Pick<{ prop?: string | undefined; }, "prop">>; } & DispatchProp<AnyAction>, { Comp: ComponentType<{}>; }>>'.
  Type '({ Comp }: { Comp: ComponentType<{}>; }) => Element' is not assignable to type 'FunctionComponent<Matching<{ Comp: ConnectedComponent<({ prop }: { prop?: string | undefined; }) => Element, Pick<{ prop?: string | undefined; }, "prop">>; } & DispatchProp<AnyAction>, { Comp: ComponentType<{}>; }>>'.
    Types of parameters '__0' and 'props' are incompatible.
      Type 'PropsWithChildren<Matching<{ Comp: ConnectedComponent<({ prop }: { prop?: string | undefined; }) => Element, Pick<{ prop?: string | undefined; }, "prop">>; } & DispatchProp<AnyAction>, { Comp: ComponentType<{}>; }>>' is not assignable to type '{ Comp: ComponentType<{}>; }'.
        Types of property 'Comp' are incompatible.
          Type 'ConnectedComponent<({ prop }: { prop?: string | undefined; }) => Element, Pick<{ prop?: string | undefined; }, "prop">>' is not assignable to type 'ComponentType<{}>'.
            Type 'ConnectedComponent<({ prop }: { prop?: string | undefined; }) => Element, Pick<{ prop?: string | undefined; }, "prop">>' is not assignable to type 'FunctionComponent<{}>'.
              Types of parameters 'props' and 'props' are incompatible.
                Type '{ children?: ReactNode; }' has no properties in common with type 'Pick<{ prop?: string | undefined; }, "prop">'.ts(2345)

It worked in the previous version.

@vkrol Does it work if you change the following?

-function B({ Comp }: { Comp: React.ComponentType }) {
+function B({ Comp }: { Comp: React.NamedExoticComponent }) {

@OliverJAsh Yes, it works. Just in case, I'll make it clear that this is not the solution :)

@OliverJAsh Just a question, does all components types on react (functions or class) now return exclusively a NamedExoticComponent? Seems to me that you are focusing on only functional components and the implementation on the new React.memo and not on all cases.

Not all developments are made exclusive with functional components...

does all components types on react (functions or class) now return exclusively a NamedExoticComponent?

connect returns the result of React.memo which is NamedExoticComponent. That is the only change.

Hello, I have same problem when I updated to 7.1.4 ...

const elementWithStore = React.createElement( ReduxProvider, { children: element, store: store } );

throws
Argument of type '{ children: React.CElement<{}, React.Component<{}, any, any>>; store: any; }' is not assignable to parameter of type 'Attributes & ProviderProps<Action<any>>'. ...

Can you give me any advice to help with solving this problem? I need pass variable element as a child of ReduxProvider this way.
How I can type it?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

demisx picture demisx  Â·  3Comments

alisabzevari picture alisabzevari  Â·  3Comments

Loghorn picture Loghorn  Â·  3Comments

Zzzen picture Zzzen  Â·  3Comments

fasatrix picture fasatrix  Â·  3Comments