Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: Cannot read property 'type' of undefined #2795

Closed
Paperfeed opened this issue Sep 15, 2020 · 3 comments · Fixed by #2802
Closed

TypeError: Cannot read property 'type' of undefined #2795

Paperfeed opened this issue Sep 15, 2020 · 3 comments · Fixed by #2802

Comments

@Paperfeed
Copy link

eslint-plugin-react v7.20.6 causes the following error:


ESLint: 7.6.0   (or 7.9.0)

TypeError: Cannot read property 'type' of undefined
Occurred while linting /path-to-file/Component.tsx:101
    at Object.isRequiredPropType (/node_modules/eslint-plugin-react/lib/util/props.js:91:29)
    at /node_modules/eslint-plugin-react/lib/util/propTypes.js:669:54
    at iterateProperties (/node_modules/eslint-plugin-react/lib/util/propTypes.js:64:7)
    at /node_modules/eslint-plugin-react/lib/util/propTypes.js:664:23
    at Array.forEach (<anonymous>)
    at DeclarePropTypesForTSTypeAnnotation.convertReturnTypeToPropTypes (/node_modules/eslint-plugin-react/lib/util/propTypes.js:653:34)
    at DeclarePropTypesForTSTypeAnnotation.searchDeclarationByName (/node_modules/eslint-plugin-react/lib/util/propTypes.js:562:14)
    at DeclarePropTypesForTSTypeAnnotation.visitTSNode (/node_modules/eslint-plugin-react/lib/util/propTypes.js:517:14)
    at DeclarePropTypesForTSTypeAnnotation.traverseDeclaredInterfaceOrTypeAlias (/node_modules/eslint-plugin-react/lib/util/propTypes.js:610:14)
    at Array.forEach (<anonymous>)

At propTypes.js it goes into the switch case for 'ObjectExpression'

switch (res.type) {
    case 'ObjectExpression':
        iterateProperties(context, res.properties, (key, value, propNode) => {
            const types = buildReactDeclarationTypes(value, key);
            types.fullName = key;
            types.name = key;
            types.node = propNode;
            types.isRequired = propsUtil.isRequiredPropType(value);
            this.declaredPropTypes[key] = types;
        });
        break;
    default:
}

with the following values:

┌───────────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────────────────┬─────────┬────────────────────┬─────────────────┬──────────┬──────────────────┬────────────────────────────────────┬──────────┬───────────┐
│    (index)    │    0     │    1     │    2     │    3     │    4     │    5     │          id          │ options │       report       │      type       │ argument │      range       │                loc                 │  parent  │  Values   │
├───────────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────────────────┼─────────┼────────────────────┼─────────────────┼──────────┼──────────────────┼────────────────────────────────────┼──────────┼───────────┤
│    context    │          │          │          │          │          │          │ 'react/display-name' │   []    │ [Function: report] │                 │          │                  │                                    │          │           │
│ resProperties │ [Object] │ [Object] │ [Object] │ [Object] │ [Object] │ [Object] │                      │         │                    │                 │          │                  │                                    │          │           │
│      key      │          │          │          │          │          │          │                      │         │                    │                 │          │                  │                                    │          │ undefined │
│     value     │          │          │          │          │          │          │                      │         │                    │                 │          │                  │                                    │          │ undefined │
│   propNode    │          │          │          │          │          │          │                      │         │                    │ 'SpreadElement' │ [Object] │ [ 13283, 13358 ] │ { start: [Object], end: [Object] } │ [Object] │           │
└───────────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────────────────┴─────────┴────────────────────┴─────────────────┴──────────┴──────────────────┴────────────────────────────────────┴──────────┴───────────┘

Which fails because the function isRequiredPropType fis called with value which is undefined
It seems to do with the TypeScript parsing in convertReturnTypeToPropTypes(node)

Now, one solution would be to simply change the isRequiredPropType function to return false when undefined is passed, like so:

function isRequiredPropType(propTypeExpression) {
  return propTypeExpression && propTypeExpression.type === 'MemberExpression' && propTypeExpression.property.name === 'isRequired';
}

But I am not entirely sure if there is an underlying problem that caused this issue. From what I can tell this component somehow hit an edge case. The component in question is a function component which is wrapped in a Redux connect() to connect to the translations state.

If the above solution is acceptable I can create a pull request for it, but otherwise I would either need to find time to look into it, or let someone more familiar with the project find the solution :)

@ljharb
Copy link
Member

ljharb commented Sep 16, 2020

What's the code being linted that causes this?

@Paperfeed
Copy link
Author

Paperfeed commented Sep 16, 2020

I've narrowed down the issue to the way the types for DispatchProps are being generated from the ReturnType of mapDispatchToProps.

We have a component as follows:

type ConnectedProps = DispatchProps &
  StateProps

const Component = ({ prop1, prop2, prop3 }: ConnectedProps) => {
  // Do stuff
  return (
    <StyledComponent>...</StyledComponent>
  )
}

const mapDispatchToProps = (dispatch: ThunkDispatch<State, null, Action>) => ({
  ...bindActionCreators(
    { prop1: importedAction, prop2: anotherImportedAction },
    dispatch,
  ),
})

const mapStateToProps = (state: State) => ({
  prop3: Selector.value(state),
})

type StateProps = ReturnType<typeof mapStateToProps>
type DispatchProps = ReturnType<typeof mapDispatchToProps>

If I comment out type DispatchProps = ReturnType<typeof mapDispatchToProps> or manually define it, the error disappears

Unfortunately I can't share the original code, as it is proprietary.

@hank121314
Copy link
Contributor

Sorry for this issue and thank you for your investigation!
I have made a pr #2802 .
Can you help me to test whether it works?
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

3 participants