Skip to content

Regression for react-hooks - Cannot read property 'parent' of null #2513

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

Closed
3 tasks done
SimenB opened this issue Sep 7, 2020 · 6 comments
Closed
3 tasks done

Regression for react-hooks - Cannot read property 'parent' of null #2513

SimenB opened this issue Sep 7, 2020 · 6 comments
Labels
external This issue is with another package, not typescript-eslint itself package: parser Issues related to @typescript-eslint/parser working as intended Issues that are closed as they are working as intended

Comments

@SimenB
Copy link
Contributor

SimenB commented Sep 7, 2020

  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.
  • I have read the FAQ and my problem is not listed.

Repro

{
  "plugins": ["react-hooks"],
  "parser": "@typescript-eslint/parser",
  "rules": {
    "react-hooks/exhaustive-deps": "error"
  }
}
import * as React from 'react';

export const List: React.FC = () => {
  const Thing = React.useMemo(() => () => null, []);

  return React.useMemo(() => {
    if (Thing) {
      return <Thing />;
    }

    return null;
  }, []);
};

Expected Result

It should not throw an error

Actual Result

TypeError: Cannot read property 'parent' of null
Occurred while linting /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions/List.tsx:6
    at getDependency (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:2228:13)
    at gatherDependenciesRecursively (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:1194:34)
    at gatherDependenciesRecursively (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:1262:13)
    at visitFunctionWithDependencies (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:1170:7)
    at visitCallExpression (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:824:11)
    at /Users/simen/repos/monorepo/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (/Users/simen/repos/monorepo/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (/Users/simen/repos/monorepo/node_modules/eslint/lib/linter/node-event-generator.js:254:26)
    at NodeEventGenerator.applySelectors (/Users/simen/repos/monorepo/node_modules/eslint/lib/linter/node-event-generator.js:283:22)

Additional Info

@typescript-eslint/parser@3.10.1 does not throw an error

  eslint:cli CLI args: [ '--debug', 'packages/folio-native-app/src/components/Transactions/List.tsx' ] +0ms
  eslint:cli Running on files +3ms
  eslint:config-array-factory Loading .eslintignore file: /Users/simen/repos/monorepo/.eslintignore +0ms
  eslint:ignore-pattern Create with: [ IgnorePattern { patterns: [ '/**/node_modules/*' ], basePath: '/Users/simen/repos/monorepo', loose: false } ] +0ms
  eslint:ignore-pattern   processed: { basePath: '/Users/simen/repos/monorepo', patterns: [ '/**/node_modules/*' ] } +2ms
  eslint:ignore-pattern Create with: [ IgnorePattern { patterns: [ '/**/node_modules/*' ], basePath: '/Users/simen/repos/monorepo', loose: false } ] +0ms
  eslint:ignore-pattern   processed: { basePath: '/Users/simen/repos/monorepo', patterns: [ '/**/node_modules/*' ] } +0ms
  eslint:file-enumerator Start to iterate files: [ 'packages/folio-native-app/src/components/Transactions/List.tsx' ] +0ms
  eslint:file-enumerator File: /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions/List.tsx +0ms
  eslint:cascading-config-array-factory Load config files for /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions. +0ms
  eslint:cascading-config-array-factory No cache found: /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions. +0ms
  eslint:config-array-factory Config file not found on /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions +4ms
  eslint:cascading-config-array-factory No cache found: /Users/simen/repos/monorepo/packages/folio-native-app/src/components. +1ms
  eslint:config-array-factory Config file not found on /Users/simen/repos/monorepo/packages/folio-native-app/src/components +0ms
  eslint:cascading-config-array-factory No cache found: /Users/simen/repos/monorepo/packages/folio-native-app/src. +0ms
  eslint:config-array-factory Config file not found on /Users/simen/repos/monorepo/packages/folio-native-app/src +0ms
  eslint:cascading-config-array-factory No cache found: /Users/simen/repos/monorepo/packages/folio-native-app. +0ms
  eslint:config-array-factory Loading package.json config file: /Users/simen/repos/monorepo/packages/folio-native-app/package.json +0ms
  eslint:config-array-factory Loading JSON config file: /Users/simen/repos/monorepo/packages/folio-native-app/package.json +0ms
  eslint:config-array-factory Error reading package.json file: /Users/simen/repos/monorepo/packages/folio-native-app/package.json +1ms
  eslint:config-array-factory Config file not found on /Users/simen/repos/monorepo/packages/folio-native-app +0ms
  eslint:cascading-config-array-factory No cache found: /Users/simen/repos/monorepo/packages. +1ms
  eslint:config-array-factory Config file not found on /Users/simen/repos/monorepo/packages +0ms
  eslint:cascading-config-array-factory No cache found: /Users/simen/repos/monorepo. +0ms
  eslint:config-array-factory Loading legacy config file: /Users/simen/repos/monorepo/.eslintrc +0ms
  eslint:config-array-factory Config file found: /Users/simen/repos/monorepo/.eslintrc +16ms
  eslint:config-array-factory Loading parser "@typescript-eslint/parser" from /Users/simen/repos/monorepo/.eslintrc +0ms
  eslint:config-array-factory Loaded: @typescript-eslint/parser@4.1.0 (/Users/simen/repos/monorepo/node_modules/@typescript-eslint/parser/dist/index.js) +1ms
  eslint:config-array-factory Loading plugin "react-hooks" from /Users/simen/repos/monorepo/.eslintrc +260ms
  eslint:config-array-factory Loaded: eslint-plugin-react-hooks@4.1.0 (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/index.js) +1ms
  eslint:config-array-factory Plugin /Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/index.js loaded in: 1ms +1ms
  eslint:cascading-config-array-factory No cache found: /Users/simen/repos. +279ms
  eslint:config-array-factory Config file not found on /Users/simen/repos +1ms
  eslint:cascading-config-array-factory No cache found: /Users/simen. +1ms
  eslint:cascading-config-array-factory Stop traversing because of considered root. +0ms
  eslint:cascading-config-array-factory Configuration was determined: ConfigArray(3) [ { type: 'config', name: 'DefaultIgnorePattern', filePath: '', criteria: null, env: undefined, globals: undefined, ignorePattern: IgnorePattern { patterns: [Array], basePath: '/Users/simen/repos/monorepo', loose: false }, noInlineConfig: undefined, parser: undefined, parserOptions: undefined, plugins: undefined, processor: undefined, reportUnusedDisableDirectives: undefined, root: undefined, rules: undefined, settings: undefined }, { type: 'config', name: '.eslintrc', filePath: '/Users/simen/repos/monorepo/.eslintrc', criteria: null, env: undefined, globals: undefined, ignorePattern: undefined, noInlineConfig: undefined, parser: { error: null, filePath: '/Users/simen/repos/monorepo/node_modules/@typescript-eslint/parser/dist/index.js', id: '@typescript-eslint/parser', importerName: '.eslintrc', importerPath: '/Users/simen/repos/monorepo/.eslintrc' }, parserOptions: undefined, plugins: { 'react-hooks': [Object] }, processor: undefined, reportUnusedDisableDirectives: undefined, root: undefined, rules: { 'react-hooks/exhaustive-deps': 'error' }, settings: undefined }, { type: 'ignore', name: '.eslintignore', filePath: '/Users/simen/repos/monorepo/.eslintignore', criteria: null, env: undefined, globals: undefined, ignorePattern: IgnorePattern { patterns: [Array], basePath: '/Users/simen/repos/monorepo', loose: true }, noInlineConfig: undefined, parser: undefined, parserOptions: undefined, plugins: undefined, processor: undefined, reportUnusedDisableDirectives: undefined, root: undefined, rules: undefined, settings: undefined } ] on /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions +1ms
  eslint:ignore-pattern Create with: [ IgnorePattern { patterns: [ '/**/node_modules/*' ], basePath: '/Users/simen/repos/monorepo', loose: false }, IgnorePattern { patterns: [ 'node_modules/', 'dist/', 'build/', 'packages/folio-common-components/lib/', 'packages/folio-common-utils/lib/', 'packages/protobank-common/lib/', 'packages/**/*.d.ts', 'packages/**/*.min.js', '.next/', '**/polyfill.js', '**/vendor/*', 'packages/**/gqltypes.ts', 'packages/**/resolver-types.ts', 'packages/stiftemaskinen-frontend/src/services/generated-types/', 'packages/folio-native-app/bin/rn-renderer/', 'packages/*/src/**/*.js', '!packages/*/src/**/__mocks__/**/*.js', '!packages/*/src/**/sw.js', 'packages/om-folio/static/**/*' ], basePath: '/Users/simen/repos/monorepo', loose: true } ] +344ms
  eslint:ignore-pattern   processed: { basePath: '/Users/simen/repos/monorepo', patterns: [ '/**/node_modules/*', 'node_modules/', 'dist/', 'build/', 'packages/folio-common-components/lib/', 'packages/folio-common-utils/lib/', 'packages/protobank-common/lib/', 'packages/**/*.d.ts', 'packages/**/*.min.js', '.next/', '**/polyfill.js', '**/vendor/*', 'packages/**/gqltypes.ts', 'packages/**/resolver-types.ts', 'packages/stiftemaskinen-frontend/src/services/generated-types/', 'packages/folio-native-app/bin/rn-renderer/', 'packages/*/src/**/*.js', '!packages/*/src/**/__mocks__/**/*.js', '!packages/*/src/**/sw.js', 'packages/om-folio/static/**/*' ] } +4ms
  eslint:ignore-pattern Check {
  filePath: '/Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions/List.tsx',
  dot: false,
  relativePath: 'packages/folio-native-app/src/components/Transactions/List.tsx',
  result: false
} +1ms
  eslint:cli-engine Lint /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions/List.tsx +0ms
  eslint:linter Linting code for /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions/List.tsx (pass 1) +0ms
  eslint:linter Verify +0ms
  eslint:linter With ConfigArray: /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions/List.tsx +0ms
  eslint:linter An error occurred while traversing +33ms
  eslint:linter Filename: /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions/List.tsx +0ms
  eslint:linter Line: 6 +0ms
  eslint:linter Parser Options: { ecmaVersion: undefined } +0ms
  eslint:linter Parser Path: /Users/simen/repos/monorepo/node_modules/@typescript-eslint/parser/dist/index.js +0ms
  eslint:linter Settings: {} +0ms

Oops! Something went wrong! :(

ESLint: 7.8.1

TypeError: Cannot read property 'parent' of null
Occurred while linting /Users/simen/repos/monorepo/packages/folio-native-app/src/components/Transactions/List.tsx:6
    at getDependency (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:2228:13)
    at gatherDependenciesRecursively (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:1194:34)
    at gatherDependenciesRecursively (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:1262:13)
    at visitFunctionWithDependencies (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:1170:7)
    at visitCallExpression (/Users/simen/repos/monorepo/node_modules/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js:824:11)
    at /Users/simen/repos/monorepo/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (/Users/simen/repos/monorepo/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (/Users/simen/repos/monorepo/node_modules/eslint/lib/linter/node-event-generator.js:254:26)
    at NodeEventGenerator.applySelectors (/Users/simen/repos/monorepo/node_modules/eslint/lib/linter/node-event-generator.js:283:22)

Versions

package version
@typescript-eslint/parser 4.1.0
TypeScript 4.0.2
ESLint 7.8.1
node 12.18.1
eslint-plugin-react-hooks 4.1.0
@SimenB SimenB added package: parser Issues related to @typescript-eslint/parser triage Waiting for team members to take a look labels Sep 7, 2020
@bradzacher bradzacher added external This issue is with another package, not typescript-eslint itself working as intended Issues that are closed as they are working as intended and removed triage Waiting for team members to take a look labels Sep 7, 2020
@bradzacher
Copy link
Member

bradzacher commented Sep 7, 2020

This is because the plugin makes assumptions about the variables declared.
Our v4 adds types as variables in the scope.

There are issues such as facebook/react#19742 tracking this. Suggest filing an issue for them if you think that issue doesn't cover it.

@SimenB
Copy link
Contributor Author

SimenB commented Sep 7, 2020

FWIW it lints fine using @typescript-eslint/parser@4.0.1 as well, it's a regression in today's 4.1.0 release. Do you still think it's an issue with the rule? If so I'm happy to open an issue over there

@bradzacher
Copy link
Member

v4.1.0 added JSX as a first-class citizen of the scope analyser (because it's a first-class citizen of TS).

This is likely why the new version has caused an issue.

@SimenB
Copy link
Contributor Author

SimenB commented Sep 7, 2020

It only happens if one useMemo is passed into another, the JSX itself doesn't seem to make a difference.

Regardless, I can open an issue over there (tomorrow, getting late here 🙂)

@bradzacher
Copy link
Member

It only happens if one useMemo is passed into another, the JSX itself doesn't seem to make a difference.

I think that it's because you're declaring const Thing = React.useMemo(() => () => null, []);, which is then passed into another useMemo and it is used as a JSX name <Thing />?


It's really hard for me to even glance at this as they bundle their tooling (eslint-plugin-react-hooks.development.js:2228:13) (I think the error happens in this function?).
I also know that those rules are massive as well (the one I linked is ~1800 lines), so I can't even begin to understand the data flow without investing significant time.

If someone can investigate and create a small, isolated repro - then I'd be happy to look into this.
My code isn't infallible so it's very possible that it's a bug in our logic.

@SimenB
Copy link
Contributor Author

SimenB commented Sep 7, 2020

As far as I got was here: https://www.runpkg.com/?eslint-plugin-react-hooks@4.1.0/cjs/eslint-plugin-react-hooks.development.js#1193 - referenceNode is null.

From debugging, the difference is that with the default espree parse we get (when first entering gatherDependenciesRecursively)

currentScope.childScopes[0].references.length === 0

whilst with the ts-eslint parser we get

currentScope.childScopes[0].references.length === 1

and it fails when it looks at reference within the child scope for whatever reason. What's correct here I have no idea 😅

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
external This issue is with another package, not typescript-eslint itself package: parser Issues related to @typescript-eslint/parser working as intended Issues that are closed as they are working as intended
Projects
None yet
Development

No branches or pull requests

2 participants