TypeScript: `forceConsistentCasingInFileNames: true` and `moduleResolution: Node16` break type reference directives on macOS if there are capital letters in the path

Bug Report

šŸ”Ž Search Terms

forceConsistentCasingInFileNames, moduleResolution, Node16, NodeNext, type reference, ā€œdiffers from already included file nameā€, ā€œonly in casingā€. Relevant issues (all resolved and predating Node16): https://github.com/microsoft/TypeScript/issues/16875, https://github.com/microsoft/TypeScript/issues/20003, https://github.com/microsoft/TypeScript/issues/17617, https://github.com/microsoft/TypeScript/issues/9824

šŸ•— Version & Regression Information

~This is the behavior in every version I tried, and I haven’t found any issues or FAQ entries about this.~ Tested only on 4.8.2, sorry. Looks like this might be recent regression after all.

āÆ Playground Link / šŸ’» Code

I can’t reproduce this in neither the playground nor the workbench nor even Linux. The problem appears only on macOS. Here’s a repro: https://github.com/alecmev/typescript-type-reference-lowercase-repro Just npm i and npx tsc.

šŸ™ Actual behavior

index.ts:2:26 - error TS1149: File name '/users/foo/repro/node_modules/@types/react/index.d.ts' differs from already included file name '/Users/Foo/repro/node_modules/@types/react/index.d.ts' only in casing.
  The file is in the program because:
    Type library referenced via 'react' from file '/Users/Foo/repro/node_modules/@babylonjs/inspector/babylon.inspector.module.d.ts'
    Imported via "react" from file '/Users/Foo/repro/node_modules/@babylonjs/inspector/babylon.inspector.module.d.ts' with packageId '@types/react/index.d.ts@18.0.17'

Note /users/foo vs. /Users/Foo.

šŸ™‚ Expected behavior

This is valid code and it works on Linux and/or without moduleResolution: Node16. An unnecessary toLowerCase happens somewhere, but I can’t really debug this further since I use Linux and had to use my colleague’s computer to create the repro. The title of the issue is only a guess, I don’t know the root of the issue.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 16 (2 by maintainers)

Commits related to this issue

Most upvoted comments

I can confirm that the same problem happens on Windows (11). I experience the same after upgrading our project from TypeScript 4.7.4 to 4.8.2. forceConsistentCasingInFileNames is set to true, and moduleResolution is set to NodeNext in our project.

I have also tested the code in alecmev’s ā€œreproā€ repository, the same happens on my Windows 11 machine when the local git working directory has uppercase characters in the path.

As mentioned by alecmev, the error message indicates that some unwanted path.toLowerCase() has taken place in the module resolution process ahead of the forceConsistentCasingInFileNames path comparison.

I have temporarily disabled forceConsistentCasingInFileNames as a temporary fix, but this compiler option is useful to ensure code written on a Windows computer will also work on Linux. Hoping for a hotfix.

can still reproduce with typescript 4.8.3 + windows 11:

src/store/postState.ts:4:26 - error TS1261: Already included file name 'c:/users/wight/documents/blog-template/src/services/post.ts' differs from file name 'C:/Users/wight/Documents/blog-template/src/services/post.ts' only in casing.
  The file is in the program because:
    Imported via '#src/services/post.js' from file 'c:/users/wight/documents/blog-template/src/store/postState.ts' with packageId 'blog-template/src/services/post.ts@0.0.0'
    Matched by include pattern '.' in 'src/tsconfig.json'
    Imported via '#src/services/post.js' from file 'c:/users/wight/documents/blog-template/src/store/postState.ts' with packageId 'blog-template/src/services/post.ts@0.0.0'
  File is ECMAScript module because 'c:/users/wight/documents/blog-template/package.json' has field "type" with value "module"

4 import { getPosts } from '#src/services/post.js';
                           ~~~~~~~~~~~~~~~~~~~~~~~

reproduction here: https://github.com/wight554/blog-template/pull/59

Sure, here’s some trace output. There’s a lot of it so I’m only including the section related to my error above.

======== Resolving module 'yargs' from '/Users/milesjohnson/Projects/web/packages/mono-env/src/bin.ts'. ========
Explicitly specified module resolution kind: 'NodeNext'.
'baseUrl' option is set to '/Users/milesjohnson/Projects/web', using this value to resolve non-relative module name 'yargs'.
'paths' option is specified, looking for a pattern to match module name 'yargs'.
'baseUrl' option is set to '/Users/milesjohnson/Projects/web', using this value to resolve non-relative module name 'yargs'.
Resolving module name 'yargs' relative to base url '/Users/milesjohnson/Projects/web' - '/Users/milesjohnson/Projects/web/yargs'.
Loading module as file / folder, candidate module location '/Users/milesjohnson/Projects/web/yargs', target file type 'TypeScript'.
File '/Users/milesjohnson/Projects/web/yargs.ts' does not exist.
File '/Users/milesjohnson/Projects/web/yargs.tsx' does not exist.
File '/Users/milesjohnson/Projects/web/yargs.d.ts' does not exist.
Directory '/Users/milesjohnson/Projects/web/yargs' does not exist, skipping all lookups in it.
File '/users/milesjohnson/projects/web/packages/mono-env/src/package.json' does not exist according to earlier cached lookups.
File '/users/milesjohnson/projects/web/packages/mono-env/package.json' exists according to earlier cached lookups.
Loading module 'yargs' from 'node_modules' folder, target file type 'TypeScript'.
Directory '/Users/milesjohnson/Projects/web/packages/mono-env/src/node_modules' does not exist, skipping all lookups in it.
File '/Users/milesjohnson/Projects/web/packages/mono-env/node_modules/yargs.ts' does not exist.
File '/Users/milesjohnson/Projects/web/packages/mono-env/node_modules/yargs.tsx' does not exist.
File '/Users/milesjohnson/Projects/web/packages/mono-env/node_modules/yargs.d.ts' does not exist.
Directory '/Users/milesjohnson/Projects/web/packages/mono-env/node_modules/@types' does not exist, skipping all lookups in it.
Directory '/Users/milesjohnson/Projects/web/packages/node_modules' does not exist, skipping all lookups in it.
Found 'package.json' at '/Users/milesjohnson/Projects/web/node_modules/yargs/package.json'.
'package.json' does not have a 'typesVersions' field.
File name '/users/milesjohnson/projects/web/node_modules/yargs/index.cjs' has a '.cjs' extension - stripping it.
File '/users/milesjohnson/projects/web/node_modules/yargs/index.cts' does not exist.
File '/users/milesjohnson/projects/web/node_modules/yargs/index.d.cts' does not exist.
File name '/users/milesjohnson/projects/web/node_modules/yargs/index.cjs' has a '.cjs' extension - stripping it.
File '/users/milesjohnson/projects/web/node_modules/yargs/index.cts' does not exist.
File '/users/milesjohnson/projects/web/node_modules/yargs/index.d.cts' does not exist.
package.json scope '/Users/milesjohnson/Projects/web/node_modules/yargs' has invalid type for target of specifier '.'
Found 'package.json' at '/Users/milesjohnson/Projects/web/node_modules/@types/yargs/package.json'.
'package.json' has a 'typesVersions' field with version-specific path mappings.
'package.json' does not have a 'typesVersions' entry that matches version '4.8'.
File '/users/milesjohnson/projects/web/node_modules/@types/yargs/index.d.ts' exist - use it as a name resolution result.
Resolving real path for '/users/milesjohnson/projects/web/node_modules/@types/yargs/index.d.ts', result '/Users/milesjohnson/Projects/web/node_modules/@types/yargs/index.d.ts'.
======== Module name 'yargs' was successfully resolved to '/users/milesjohnson/projects/web/node_modules/@types/yargs/index.d.ts' with Package ID '@types/yargs/index.d.ts@17.0.11'. ========

This seems related to #45509 -> #45096 -> #10340