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

Module resolution behaves differently when typeRoots is specified #59329

Open
wjhsf opened this issue Jul 17, 2024 · 3 comments
Open

Module resolution behaves differently when typeRoots is specified #59329

wjhsf opened this issue Jul 17, 2024 · 3 comments
Assignees
Labels
Needs Investigation This issue needs a team member to investigate its status.

Comments

@wjhsf
Copy link

wjhsf commented Jul 17, 2024

πŸ”Ž Search Terms

typeRoots, module resolution, moduleResolution, bundler

πŸ•— Version & Regression Information

  • This changed between versions 5.0.4 and 5.1.3 (variants with Preserve since 5.4.2)

⏯ Playground Link

No response

πŸ’» Code

No response

πŸ™ Actual behavior

Setting typeRoots to ./node_modules/@types changes how modules are resolved when using the following compiler options:

  • moduleResolution: Node16, module: Node16
  • moduleResolution: Node10, module: Preserve
  • moduleResolution: Bundler, module: ES2015 | ES2020 | ES2022 | ESNext | Preserve

πŸ™‚ Expected behavior

Setting typeRoots to ./node_modules/@types should not change how modules are resolved.

Additional information about the issue

Clone this gist and execute setup.sh to see a minimal reproduction. It sets up a package with various export types, and tries to compile a file with corresponding imports using various module/moduleResolution combinations. Not all imports are expected to work for all combinations, but the errors are expected to be the same regardless of whether typeRoots is specified. If the errors are different, the script will log the errors along with the compiler options used. (No output from the script means there were no mismatched errors.)

Sample output:

{ module: 'Preserve', moduleResolution: 'Bundler' }
=== no typeRoots ===
index.ts(1,22): error TS2307: Cannot find module 'pkg' or its corresponding type declarations.
index.ts(2,30): error TS2307: Cannot find module 'pkg/index' or its corresponding type declarations.
index.ts(3,32): error TS2307: Cannot find module 'pkg/index.js' or its corresponding type declarations.
index.ts(4,32): error TS2307: Cannot find module 'pkg/internal' or its corresponding type declarations.
index.ts(5,34): error TS2307: Cannot find module 'pkg/internal.js' or its corresponding type declarations.
index.ts(6,32): error TS2307: Cannot find module 'pkg/external' or its corresponding type declarations.
index.ts(7,34): error TS2307: Cannot find module 'pkg/external.js' or its corresponding type declarations.
index.ts(8,31): error TS2307: Cannot find module 'pkg/exports' or its corresponding type declarations.

== with typeRoots ==
index.ts(8,31): error TS2307: Cannot find module 'pkg/exports' or its corresponding type declarations.

{ module: 'Preserve', moduleResolution: 'Node10' }
=== no typeRoots ===
index.ts(1,22): error TS2307: Cannot find module 'pkg' or its corresponding type declarations.
index.ts(2,30): error TS2307: Cannot find module 'pkg/index' or its corresponding type declarations.
index.ts(3,32): error TS2307: Cannot find module 'pkg/index.js' or its corresponding type declarations.
index.ts(4,32): error TS2307: Cannot find module 'pkg/internal' or its corresponding type declarations.
index.ts(5,34): error TS2307: Cannot find module 'pkg/internal.js' or its corresponding type declarations.
index.ts(6,32): error TS2307: Cannot find module 'pkg/external' or its corresponding type declarations.
index.ts(7,34): error TS2307: Cannot find module 'pkg/external.js' or its corresponding type declarations.
index.ts(8,31): error TS2307: Cannot find module 'pkg/exports' or its corresponding type declarations.

== with typeRoots ==
index.ts(8,31): error TS2307: Cannot find module 'pkg/exports' or its corresponding type declarations.
@RyanCavanaugh
Copy link
Member

Can you specify exactly one config which you think should behave differently? We're also not super keen on running .sh files; a concrete set of flat files which we can copy locally would be preferred.

@RyanCavanaugh RyanCavanaugh added the Needs More Info The issue still hasn't been fully clarified label Jul 26, 2024
wjhsf added a commit to wjhsf/typescript-issue-59329 that referenced this issue Jul 27, 2024
wjhsf added a commit to wjhsf/typescript-issue-59329 that referenced this issue Jul 27, 2024
@wjhsf
Copy link
Author

wjhsf commented Jul 27, 2024

Here's a proper repo you can clone. It's not quite flat because typeRoots needs a directory structure.

This is the tsconfig.json from the repo:

{
  "files": ["index.ts"],
  "compilerOptions": {
    "noEmit": true,

    // When "typeRoots" is not specified, this project has 8 compiler errors.
    // When "typeRoots" is specified, this project has 1 compiler error.
    // "typeRoots": ["./node_modules/@types"],

    "module": "Node16",
    "moduleResolution": "Node16",
    // Preserve/Node10, Preserve/Bundler, and ES2015+/Bundler all have
    // differences in behavior depending on the presence of "typeRoots".
    // "moduleResolution": "Node10",
    // "moduleResolution": "Bundler"
    // "module": "Preserve",
    // "module": "ES2015",
    // "module": "ES2020",
    // "module": "ES2022",
    // "module": "ESNext",
  }
}

I also noticed that different combinations of "type": "module" or "type": "commonjs" in the root package.json and in typeRoots/pkg/package.json result in different errors being reported when you have typeRoots set in the tsconfig. That's expected behavior. However, if you don't have typeRoots set, then the errors are always the same. Which seems weird.

Root package typeRoots package Errors
cjs cjs TS2307
cjs esm TS1479, TS1479, TS1479, TS1479, TS1479, TS1479, TS1479, TS2307
esm cjs TS2307, TS2307, TS2307, TS2307
esm esm TS2307, TS2307, TS2307, TS2307

When typeRoots is not specified, the set of errors is "TS2307, TS2307, TS2307, TS2307, TS2307, TS2307, TS2307, TS2307" in all four scenarios.


Perhaps unsurprisingly, I've found that it's the presence of "exports" in the package.json that is causing the issue. When that key is removed, then the behavior of tsc is the same regardless of whether typeRoots is specified.

@RyanCavanaugh RyanCavanaugh added Needs Investigation This issue needs a team member to investigate its status. and removed Needs More Info The issue still hasn't been fully clarified labels Jul 29, 2024
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 5.7.0 milestone Jul 29, 2024
@andrewbranch
Copy link
Member

I think this is a duplicate of #47444. I tried to fix it at #58638 and the breaks looked untenable. It may be worth experimenting with resolving "exports" first and falling back to resolving "types", but I held off since non-type-reference module resolution does not continue with fallbacks if "exports" resolution fails, and keeping that consistency with the spec is a plus.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Investigation This issue needs a team member to investigate its status.
Projects
None yet
Development

No branches or pull requests

3 participants