Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Missing types when using project references and single run inference (allowAutomaticSingleRunInference) #3851

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
gcangussu opened this issue Sep 6, 2021 · 7 comments
Labels
accepting prs Go ahead, send a pull request that resolves this issue bug Something isn't working help wanted Extra attention is needed locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. package: typescript-estree Issues related to @typescript-eslint/typescript-estree
Milestone

Comments

@gcangussu
Copy link
Contributor

  • 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

We need a few files to reproduce this:

Reproduction is available here: https://github.com/gcangussu/typescript-eslint-bug-repro

Expected Result

Tests passing

$ npm --silent test && echo $?
0

We can see that it works with single run inference disabled with

npm run test-without-single-run-inference

Actual Result

npm --silent test && echo $?

/Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src/app.ts
   9:7   error  Unsafe assignment of an `any` value                @typescript-eslint/no-unsafe-assignment
  10:30  error  Invalid type "any" of template literal expression  @typescript-eslint/restrict-template-expressions
  10:30  error  Unsafe member access .toFixed on an `any` value    @typescript-eslint/no-unsafe-member-access
  10:30  error  Unsafe call of an `any` typed value                @typescript-eslint/no-unsafe-call

✖ 4 problems (4 errors, 0 warnings)

Additional Info

It seems that with single run the project (tsconfig.json) is not being correctly taken into consideration. Checking the output of packages/bar/src/public/utils.ts shows that it is correctly typed. However, when it is imported from another package (foo), ts-eslint fails to find its type. Although, it works fine when imported from within the same package.

I've kept only the rule @typescript-eslint/no-unsafe-assignment and run npx eslint --ext=.ts --debug packages/foo/src/app.ts.

Output, click to expand
2021-09-06T20:51:40.919Z eslint:cli CLI args: [ '--ext=.ts', '--debug', 'packages/foo/src/app.ts' ]
2021-09-06T20:51:40.921Z eslint:cli Running on files
2021-09-06T20:51:40.930Z eslintrc:config-array-factory Loading .eslintignore file: /Users/gabriel/Repos/typescript-eslint-bug-repro/.eslintignore
2021-09-06T20:51:40.931Z eslintrc:ignore-pattern Create with: [ IgnorePattern { patterns: [ '/**/node_modules/*' ], basePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro', loose: false } ]
2021-09-06T20:51:40.933Z eslintrc:ignore-pattern   processed: { basePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro', patterns: [ '/**/node_modules/*' ] }
2021-09-06T20:51:40.933Z eslintrc:ignore-pattern Create with: [ IgnorePattern { patterns: [ '/**/node_modules/*' ], basePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro', loose: false } ]
2021-09-06T20:51:40.933Z eslintrc:ignore-pattern   processed: { basePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro', patterns: [ '/**/node_modules/*' ] }
2021-09-06T20:51:40.934Z eslint:file-enumerator Start to iterate files: [ 'packages/foo/src/app.ts' ]
2021-09-06T20:51:40.934Z eslint:file-enumerator File: /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src/app.ts
2021-09-06T20:51:40.934Z eslintrc:cascading-config-array-factory Load config files for /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src.
2021-09-06T20:51:40.934Z eslintrc:cascading-config-array-factory No cache found: /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src.
2021-09-06T20:51:40.934Z eslintrc:config-array-factory Config file not found on /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src
2021-09-06T20:51:40.935Z eslintrc:cascading-config-array-factory No cache found: /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo.
2021-09-06T20:51:40.935Z eslintrc:config-array-factory Config file not found on /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo
2021-09-06T20:51:40.935Z eslintrc:cascading-config-array-factory No cache found: /Users/gabriel/Repos/typescript-eslint-bug-repro/packages.
2021-09-06T20:51:40.935Z eslintrc:config-array-factory Config file not found on /Users/gabriel/Repos/typescript-eslint-bug-repro/packages
2021-09-06T20:51:40.935Z eslintrc:cascading-config-array-factory No cache found: /Users/gabriel/Repos/typescript-eslint-bug-repro.
2021-09-06T20:51:40.935Z eslintrc:config-array-factory Loading JSON config file: /Users/gabriel/Repos/typescript-eslint-bug-repro/.eslintrc.json
2021-09-06T20:51:40.935Z eslintrc:config-array-factory Config file found: /Users/gabriel/Repos/typescript-eslint-bug-repro/.eslintrc.json
2021-09-06T20:51:40.936Z eslintrc:config-array-factory Loading parser "@typescript-eslint/parser" from /Users/gabriel/Repos/typescript-eslint-bug-repro/.eslintrc.json
2021-09-06T20:51:40.936Z eslintrc:config-array-factory Loaded: @typescript-eslint/[email protected] (/Users/gabriel/Repos/typescript-eslint-bug-repro/node_modules/@typescript-eslint/parser/dist/index.js)
2021-09-06T20:51:41.136Z eslintrc:config-array-factory Loading plugin "@typescript-eslint" from /Users/gabriel/Repos/typescript-eslint-bug-repro/.eslintrc.json
2021-09-06T20:51:41.137Z eslintrc:config-array-factory Loaded: @typescript-eslint/[email protected] (/Users/gabriel/Repos/typescript-eslint-bug-repro/node_modules/@typescript-eslint/eslint-plugin/dist/index.js)
2021-09-06T20:51:41.274Z eslintrc:config-array-factory Plugin /Users/gabriel/Repos/typescript-eslint-bug-repro/node_modules/@typescript-eslint/eslint-plugin/dist/index.js loaded in: 137ms
2021-09-06T20:51:41.274Z eslintrc:cascading-config-array-factory Stop traversing because of 'root:true'.
2021-09-06T20:51:41.276Z eslintrc: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/gabriel/Repos/typescript-eslint-bug-repro', loose: false }, noInlineConfig: undefined, parser: undefined, parserOptions: undefined, plugins: undefined, processor: undefined, reportUnusedDisableDirectives: undefined, root: undefined, rules: undefined, settings: undefined }, { type: 'config', name: '.eslintrc.json', filePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro/.eslintrc.json', criteria: null, env: undefined, globals: undefined, ignorePattern: undefined, noInlineConfig: undefined, parser: { error: null, filePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro/node_modules/@typescript-eslint/parser/dist/index.js', id: '@typescript-eslint/parser', importerName: '.eslintrc.json', importerPath: '/Users/gabriel/Repos/typescript-eslint-bug-repro/.eslintrc.json' }, parserOptions: { allowAutomaticSingleRunInference: true, project: [Array] }, plugins: { '@typescript-eslint': [Object] }, processor: undefined, reportUnusedDisableDirectives: undefined, root: true, rules: { '@typescript-eslint/no-unsafe-assignment': 'error' }, settings: undefined }, { type: 'ignore', name: '.eslintignore', filePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro/.eslintignore', criteria: null, env: undefined, globals: undefined, ignorePattern: IgnorePattern { patterns: [Array], basePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro', loose: true }, noInlineConfig: undefined, parser: undefined, parserOptions: undefined, plugins: undefined, processor: undefined, reportUnusedDisableDirectives: undefined, root: undefined, rules: undefined, settings: undefined } ] on /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src
2021-09-06T20:51:41.276Z eslintrc:ignore-pattern Create with: [ IgnorePattern { patterns: [ '/**/node_modules/*' ], basePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro', loose: false }, IgnorePattern { patterns: [ 'build/' ], basePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro', loose: true } ]
2021-09-06T20:51:41.276Z eslintrc:ignore-pattern   processed: { basePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro', patterns: [ '/**/node_modules/*', 'build/' ] }
2021-09-06T20:51:41.277Z eslintrc:ignore-pattern Check {
  filePath: '/Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src/app.ts',
  dot: false,
  relativePath: 'packages/foo/src/app.ts',
  result: false
}
2021-09-06T20:51:41.277Z eslint:cli-engine Lint /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src/app.ts
2021-09-06T20:51:41.277Z eslint:linter Linting code for /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src/app.ts (pass 1)
2021-09-06T20:51:41.277Z eslint:linter Verify
2021-09-06T20:51:41.277Z eslint:linter With ConfigArray: /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src/app.ts
2021-09-06T20:51:42.117Z eslint:linter Generating fixed text for /Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src/app.ts (pass 1)
2021-09-06T20:51:42.117Z eslint:source-code-fixer Applying fixes
2021-09-06T20:51:42.117Z eslint:source-code-fixer shouldFix parameter was false, not attempting fixes
2021-09-06T20:51:42.118Z eslint:file-enumerator Complete iterating files: ["packages/foo/src/app.ts"]
2021-09-06T20:51:42.118Z eslint:cli-engine Linting complete in: 1184ms

/Users/gabriel/Repos/typescript-eslint-bug-repro/packages/foo/src/app.ts
  9:7  error  Unsafe assignment of an `any` value  @typescript-eslint/no-unsafe-assignment

✖ 1 problem (1 error, 0 warnings)

Relates to #3528

Versions

package version
@typescript-eslint/typescript-estree 4.30.0
@typescript-eslint/eslint-plugin 4.30.0
@typescript-eslint/parser 4.30.0
TypeScript 4.4.2
node 14.17.6
@gcangussu gcangussu added package: typescript-estree Issues related to @typescript-eslint/typescript-estree triage Waiting for team members to take a look labels Sep 6, 2021
@bradzacher
Copy link
Member

We don't consume project references from this project - we never have - #2094.
Which is why I'm very surprised that your config lints.

In a nutshell - when in single-run mode we do a different

It looks like there's something internal to TS which means that:
ts.getParsedCommandLineOfConfigFile(...).fileNames returns

[
  '~/typescript-eslint-bug-repro-main/packages/bar/src/internal/utils.ts',
  '~/typescript-eslint-bug-repro-main/packages/bar/src/public/utils.ts',
  '~/typescript-eslint-bug-repro-main/packages/foo/src/app.ts'
]

In comparison the program created by ts.createWatchProgram instead returns

[
  '~/typescript-eslint-bug-repro-main/build/packages/bar/src/internal/utils.d.ts',
  '~/typescript-eslint-bug-repro-main/build/packages/bar/src/public/utils.d.ts',
  '~/typescript-eslint-bug-repro-main/packages/foo/src/app.ts'
]

I'm not sure why they behave differently.

As far as I can tell - this is likely related to your paths config. If it were due to the project references or single run inference then our linting within this project (which uses both) would be broken.

I won't have any bandwidth to look into this more sorry - happy to provide pointers if you'd like to dig in more.

@bradzacher bradzacher added bug Something isn't working and removed triage Waiting for team members to take a look labels Sep 20, 2021
@gcangussu
Copy link
Contributor Author

Thanks for taking a look at it. And sure, If you could provide some points of interest on the code that would be great for me to investigate.

@bradzacher
Copy link
Member

bradzacher commented Sep 20, 2021

  1. This function is the entrypoint into the parser from ESLint:
  2. This code is used by the "single run inference" to construct a program
  3. This code is used by the non-single-run codepath to construct the "watch program"

in a nutshell - the code follows this structure:

  1. parseAndGenerateServices ((1) above)
  2. if is single run, create an iterable for each of the tsconfigs provided ((2) above)
  3. else create a "watch program" for each of the tsconfigs provided ((3) above)

It's a little more complicated than that because we lazily compute everything, but that's it in a nutshell!

It looks like for some reason TS's ts.getParsedCommandLineOfConfigFile API (used in (2) above) resolves the list of files without considering project references - leading to files that exist outside the program (causing errors).

You might need to dig into the TS codebase a little to figure out if we're calling the API incorrectly, or if we're calling the ts.createProgram API incorrectly, or if this is just something weird in TS we'd need to work around or report upstream.

@JoshuaKGoldberg JoshuaKGoldberg added the accepting prs Go ahead, send a pull request that resolves this issue label Oct 25, 2021
@JoshuaKGoldberg
Copy link
Member

JoshuaKGoldberg commented Apr 16, 2023

Sadly, I think this is blocked on us being able to know whether ESLint is in fixer mode or not. I think that makes this issue both/partially-each:

🥲, as always. Someone please say something if there's a workaround we can go with!

@JoshuaKGoldberg JoshuaKGoldberg added duplicate This issue or pull request already exists blocked by external API Blocked by a tool we depend on exposing an API, such as TypeScript's Type Relationship API and removed accepting prs Go ahead, send a pull request that resolves this issue labels Apr 16, 2023
@JoshuaKGoldberg JoshuaKGoldberg changed the title Missing types when using project references and single run inference Missing types when using project references and single run inference (allowAutomaticSingleRunInference) Dec 24, 2023
@JoshuaKGoldberg
Copy link
Member

JoshuaKGoldberg commented Dec 24, 2023

Well, the ESLint RFC was declined and no action has happened on that front since then (😞). But we would greatly benefit from being able to enable allowAutomaticSingleRunInference by default.

A hunch: I bet we can do something "clever" internally to turn off allowAutomaticSingleRunInference if linting re-runs in a manner suspiciously like --fix. Ah, this one is not --fix, it's project references. So I bet using useProjectService might be a good workaround, given that project references aren't supported otherwise. Thoughts @bradzacher?~

Marking as accepting prs in the meantime & adding to the v7 v8 milestone.

@JoshuaKGoldberg JoshuaKGoldberg added accepting prs Go ahead, send a pull request that resolves this issue and removed duplicate This issue or pull request already exists blocked by external API Blocked by a tool we depend on exposing an API, such as TypeScript's Type Relationship API labels Dec 24, 2023
@JoshuaKGoldberg JoshuaKGoldberg added this to the 7.0.0 milestone Dec 24, 2023
@bradzacher
Copy link
Member

Honestly I don't know what the issue is so I don't know what would fix it. There's a discrepancy somewhere between the two code paths that causes this.
The project service wouldn't be a solution, I believe - it should perform about the same and do about the same worn as the existing solution.

Someone just needs to answer the question of why the two return different paths.

@JoshuaKGoldberg
Copy link
Member

JoshuaKGoldberg commented Apr 15, 2024

Ok! Following up on this: I now more strongly believe the project service (EXPERIMENTAL_useProjectService / useProjectService) is the solution here. I updated the repro repo's dependency versions to latest and enabled it in the .eslintrc.json. Running npm run test showed no erroneous lint complaints. Whoo!

I would love to know why the watch vs. non-watch programs go down different code paths. But given that the new project service resolves the issue and we don't actually support project references otherwise, I don't think we need to take a strong look at this. Closing as resolved.

  "parserOptions": {
    "allowAutomaticSingleRunInference": true,
-   "project": ["./packages/*/tsconfig.json"]
+   "EXPERIMENTAL_useProjectService": true
  },

Someone please yell at me if we actually do have a need to investigate more deeply! 💜

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 23, 2024
@bradzacher bradzacher added the locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. label Apr 14, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepting prs Go ahead, send a pull request that resolves this issue bug Something isn't working help wanted Extra attention is needed locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. package: typescript-estree Issues related to @typescript-eslint/typescript-estree
Projects
None yet
Development

No branches or pull requests

3 participants