-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Module resolution: "nodenext" fails to follow imports in .d.ts files of dependency packages that are "type": "module" #62490
Description
Demo Repo
https://github.com/Harris-Miller/moduleResolutionIssue
Which of the following problems are you reporting?
The module specifier resolves at runtime, but not at build time
Demonstrate the defect described above with a code sample.
https://github.com/Harris-Miller/moduleResolutionIssue/blob/main/app/src/fib.ts#L1
import { add, append } from 'test-lib';Produces error TS2305: Module '"test-lib"' has no exported member 'add'.
add comes from a local dependency; the declaration file can be found in dist/math.d.ts
If you search for the word "math" in my attached tsc --traceResolution you'll find
Loading module as file / folder, candidate module location '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/lib/dist/math', target file types: TypeScript, JavaScript, Declaration, JSON.
Directory '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/lib/dist/math' does not exist, skipping all lookups in it.
======== Module name './math' was not resolved. ========
Import to the failed resolution is that libs/package.json is configured as "type": "module"
It appears that when using "moduleResolution": "nodenext", when resolving files of dependencies, it's applying resolution for each depent package to that package's package.json#type value. That makes sense for runtime code, but breaks for declaration .d.ts files, which can never be built with important statements containing file extensions
Run tsc --showConfig and paste its output here
Run tsc --traceResolution and paste its output here
File '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/src/package.json' does not exist.
Found 'package.json' at '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/package.json'.
======== Resolving module 'react/jsx-runtime' from '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/src/fib.ts'. ========
Explicitly specified module resolution kind: 'NodeNext'.
Resolving in CJS mode with conditions 'require', 'types', 'node'.
File '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/src/package.json' does not exist according to earlier cached lookups.
File '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/package.json' exists according to earlier cached lookups.
...
======== Resolving module 'test-lib' from '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/src/fib.ts'. ========
Explicitly specified module resolution kind: 'NodeNext'.
Resolving in CJS mode with conditions 'require', 'types', 'node'.
File '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/src/package.json' does not exist according to earlier cached lookups.
File '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/package.json' exists according to earlier cached lookups.
Loading module 'test-lib' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration, JSON.
Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.
Directory '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/src/node_modules' does not exist, skipping all lookups in it.
Found 'package.json' at '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/node_modules/test-lib/package.json'.
Entering conditional exports.
Matched 'exports' condition 'types'.
Using 'exports' subpath '.' with target './dist/index.d.ts'.
File '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/node_modules/test-lib/dist/index.d.ts' exists - use it as a name resolution result.
'package.json' does not have a 'peerDependencies' field.
Resolved under condition 'types'.
Exiting conditional exports.
Resolving real path for '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/node_modules/test-lib/dist/index.d.ts', result '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/lib/dist/index.d.ts'.
======== Module name 'test-lib' was successfully resolved to '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/lib/dist/index.d.ts' with Package ID 'test-lib/dist/index.d.ts@1.0.0'. ========
File '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/lib/dist/package.json' does not exist.
Found 'package.json' at '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/lib/package.json'.
======== Resolving module './math' from '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/lib/dist/index.d.ts'. ========
Explicitly specified module resolution kind: 'NodeNext'.
Resolving in ESM mode with conditions 'import', 'types', 'node'.
Loading module as file / folder, candidate module location '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/lib/dist/math', target file types: TypeScript, JavaScript, Declaration, JSON.
Directory '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/lib/dist/math' does not exist, skipping all lookups in it.
======== Module name './math' was not resolved. ========
File '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/src/package.json' does not exist according to earlier cached lookups.
File '/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/package.json' exists according to earlier cached lookups.
...
src/fib.ts(1,10): error TS2305: Module '"test-lib"' has no exported member 'add'.
Paste the package.json of the importing module, if it exists
{
"name": "test-app",
"private": true,
"version": "1.0.0",
"description": "",
"main": "dist/main.js",
"scripts": {
"build": "tsc",
"start": "node ./dist/main.js",
"typecheck": "tsc --noEmit"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"test-lib": "file://../lib"
},
"devDependencies": {
"@types/node": "^22.18.6",
"tslib": "^2.8.1",
"typescript": "^5.9.2"
}
}Paste the package.json of the target module, if it exists
{
"name": "test-lib",
"type": "module",
"version": "1.0.0",
"description": "",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"files": [
"dist"
],
"scripts": {
"build": "rollup -c",
"typecheck": "tsc --noEmit"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@rollup/plugin-typescript": "^12.1.4",
"@types/node": "^22.18.6",
"rollup": "^4.52.2",
"tslib": "^2.8.1",
"typescript": "^5.9.2"
}
}Any other comments can go here
I removed the unimportant bits in my pasted tsc --traceResolition for brevity
Typescript doesn't have a problem resolving "types": "./dist/index.d.ts" since there is an extension there, the problem is for then that file imports others without extensions, which is always
{ "compilerOptions": { "rootDir": "./src", "outDir": "./dist", "module": "nodenext", "moduleResolution": "nodenext", "types": [], "sourceMap": false, "declaration": false, "declarationMap": false, "noUncheckedIndexedAccess": false, "exactOptionalPropertyTypes": true, "strict": true, "jsx": "react-jsx", "verbatimModuleSyntax": false, "isolatedModules": true, "noUncheckedSideEffectImports": true, "moduleDetection": "force", "skipLibCheck": true, "target": "esnext", "esModuleInterop": true, "allowSyntheticDefaultImports": true, "resolvePackageJsonExports": true, "resolvePackageJsonImports": true, "resolveJsonModule": true, "preserveConstEnums": true, "useDefineForClassFields": true, "noImplicitAny": true, "noImplicitThis": true, "strictNullChecks": true, "strictFunctionTypes": true, "strictBindCallApply": true, "strictPropertyInitialization": true, "strictBuiltinIteratorReturn": true, "alwaysStrict": true, "useUnknownInCatchVariables": true }, "files": [ "./src/fib.ts", "./src/main.ts" ], "exclude": [ "/Users/hmiller/Projects/harris-miller/moduleResolutionIssue/app/dist" ] }