Typescript + React/Redux: Property "XXX" does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes
Asked Answered
N

7

139

I'm working on a project with Typescript, React and Redux (all running in Electron), and I've run into a problem when I'm including one class based component in another and trying to pass parameters between them. Loosely speaking, I've got the following structure for the container component:

class ContainerComponent extends React.Component<any,any> {
  ..
  render() {
    const { propToPass } = this.props;
    ...
    <ChildComponent propToPass={propToPass} />
    ...
  }
}

....
export default connect(mapStateToProps, mapDispatchToProps)(ContainerComponent);

And the child component:

interface IChildComponentProps extends React.Props<any> {
  propToPass: any
}

class ChildComponent extends React.Component<IChildComponentProps, any> {
  ...
}

....
export default connect(mapStateToProps, mapDispatchToProps)(ChildComponent);

Obviously I'm only including the basics and there is much more to both of these classes but I'm still getting an error when I try and run what looks to me like valid code. The exact error that I'm getting:

TS2339: Property 'propToPass' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<{}, ComponentState>> & Readonly<{ childr...'.

When I first encountered the error I thought it was because I wasn't passing in an interface defining my props, but I created that (as you can see above) and it still doesn't work. I'm wondering, is there something I'm missing?

When I exclude the ChildComponent prop from the code in the ContainerComponent, it renders just fine (aside from my ChildComponent not having a critical prop) but with it in the JSX Typescript refuses to compile it. I think it might have something to do with the connect wrapping based on this article, but the problems in that article occurred in the index.tsx file and were a problem with the provider, and I'm getting my problems elsewhere.

Nardi answered 7/3, 2017 at 20:32 Comment(0)
N
72

So after reading through some related answers (specifically this one and this one and looking at @basarat's answer to the question, I managed to find something that works for me. It looks (to my relatively new React eyes) like Connect was not supplying an explicit interface to the container component, so it was confused by the prop that it was trying to pass.

So the container component stayed the same, but the child component changed a bit:

interface IChildComponentProps extends React.Props<any> {
  ... (other props needed by component)
}

interface PassedProps extends React.Props<any> {
  propToPass: any
}

class ChildComponent extends React.Component<IChildComponentProps & PassedProps, any> {
  ...
}

....
export default connect<{}, {}, PassedProps>(mapStateToProps, mapDispatchToProps)    (ChildComponent);

The above managed to work for me. Passing explicitly the props that the component is expecting from the container seemed to work and both components rendered properly.

NOTE: I know this is a very simplistic answer and I'm not exactly sure WHY this works, so if a more experienced React ninja wants to drop some knowledge on this answer I'd be happy to amend it.

Nardi answered 7/3, 2017 at 22:56 Comment(4)
But React.Props has been deprecated !!Ossuary
medium.com/knerd/…Aristate
After searching about this issue for an embarrassingly long time, I found the key to fixing this is in that final change to connect - updating connect's interface to include the additional parameters being supplied addresses the issue entirely, no other changes required (at least for my code).Specious
this with functional components would be idealNewfangled
H
11

What worked for me is simply changing the child Component type from React.FC to JSX.Element

Before (warning)

const Component: React.FC = () => {

After (no warning)

const Component = (): JSX.Element => {

Hidrosis answered 20/10, 2022 at 12:21 Comment(1)
this was my issue as well. Thanks for the help!Calie
M
3

Double check the newly added object types. When object type is not exactly as expected such error is thrown.

Ex. Type of props mentioned in component must match with type of props which are passed to that component.

Modlin answered 2/1, 2021 at 4:59 Comment(1)
I believe while this answer is helpful it lacks some example. In my case, while using functional components, I forgot to destructure the props, i.e. I did const ChildComponent = (desiredProp) => ... instead of const ChildComponent = ({desiredProp}) => ... and thus getting the error.Aesculapian
M
2

In my case, I was building a typescript component that imported a component that was in javascript that uses connect.

Here was a quick way for me to fix the error.

// User is a javascript component
import _User from "./User";

// Inject types that this component accepts
const User = _User as unknown as React.JSXElementConstructor<{
 userId: string
}>;

const UserProfile = () => {
  const user = useCurrentUser();
  return (
    <div className="flex items-center justify-center">
      <User userId={user.userId} />
    </div>
  );
}

Hope this helps you!

Molina answered 31/3, 2022 at 17:46 Comment(1)
this one saves me, thanks!Crumpton
P
1

Make your child Component extend React.Component with the type you want or "any" type. ex: "extends React.Component<any> {...}"

export class ChildComponent extends React.Component<T> {
 render() {
  return (
    <button className="square">
      {this.props.value}
    </button>
  );
 }
}

In Parent component you could then pass the value, ex:

renderSquare(i: Number) { return <ChildComponent value={i}/>; }

Check https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/class_components/ for more info

Precursor answered 25/2, 2021 at 12:42 Comment(0)
E
0

In my case the fix is to set generic type for React.FC

interface SearchActionProps {
    onClick: () => void
}

old code that gives me "Property does not exist on type 'IntrinsicAttributes'":

export const SearchActionButton: React.FC = ({onClick}: SearchActionProps) => { 
    ... 
}

new code that works fine:

export const SearchActionButton: React.FC<SearchActionProps> = ({onClick}) => { 
    ... 
}
Example answered 10/1 at 14:23 Comment(0)
O
-5

Instead of export default connect(mapStateToProps, mapDispatchToProps)(ChildComponent);, prefer the connect decorator https://github.com/alm-tools/alm/blob/00f2f94efd3810af8a80a49f968c2ebdeb955399/src/app/fileTree.tsx#L136-L146

@connect((state: StoreState): Props => {
    return {
        filePaths: state.filePaths,
        filePathsCompleted: state.filePathsCompleted,
        rootDir: state.rootDir,
        activeProjectFilePathTruthTable: state.activeProjectFilePathTruthTable,
        fileTreeShown: state.fileTreeShown,
    };
})

Where connect is defined here https://github.com/alm-tools/alm/blob/00f2f94efd3810af8a80a49f968c2ebdeb955399/src/typings/react-redux/react-redux.d.ts#L6-L36

Why?

Seems like the definitions you are using are probably out of date or invalid (perhaps poorly authored).

Opinicus answered 7/3, 2017 at 21:14 Comment(1)
It looks like connect on the child component was definitely the problem, but I found a way to solve the issue without changing the typings I was using. Using the solution in this link I managed to change my connect to: connect<{}, {}, PassedProps> Where PassedProps is the prop that the component gets from it's parent container.Nardi

© 2022 - 2024 — McMap. All rights reserved.