diff --git a/internal/compiler/fileloader.go b/internal/compiler/fileloader.go index ee2daa137f0..c4836b72364 100644 --- a/internal/compiler/fileloader.go +++ b/internal/compiler/fileloader.go @@ -180,7 +180,9 @@ func (p *fileLoader) resolveAutomaticTypeDirectives(containingFileName string) ( toParse = make([]resolvedRef, 0, len(automaticTypeDirectiveNames)) typeResolutionsInFile = make(module.ModeAwareCache[*module.ResolvedTypeReferenceDirective], len(automaticTypeDirectiveNames)) for _, name := range automaticTypeDirectiveNames { - resolutionMode := core.ModuleKindNodeNext + // Under node16/nodenext module resolution, load `types`/ata include names as cjs resolution results by passing an `undefined` mode. + // Under bundler module resolution, this also triggers the "import" condition to be used. + resolutionMode := core.ResolutionModeNone resolved, trace := p.resolver.ResolveTypeReferenceDirective(name, containingFileName, resolutionMode, nil) typeResolutionsInFile[module.ModeAwareCacheKey{Name: name, Mode: resolutionMode}] = resolved typeResolutionsTrace = append(typeResolutionsTrace, trace...) diff --git a/testdata/baselines/reference/compiler/automaticTypeDirectiveResolutionBundler.symbols b/testdata/baselines/reference/compiler/automaticTypeDirectiveResolutionBundler.symbols new file mode 100644 index 00000000000..025316de563 --- /dev/null +++ b/testdata/baselines/reference/compiler/automaticTypeDirectiveResolutionBundler.symbols @@ -0,0 +1,30 @@ +//// [tests/cases/compiler/automaticTypeDirectiveResolutionBundler.ts] //// + +=== /index.ts === +// The automatic type directive "pkg" from @types should resolve to esm.d.mts +// because bundler resolution uses the "import" condition. +// If the wrong file is resolved, we'll get a type error due to conflicting declarations. +import type { PkgType } from "pkg"; +>PkgType : Symbol(PkgType, Decl(index.ts, 3, 13)) + +// This should work if esm.d.mts is correctly resolved +const x: PkgType = { esm: true }; +>x : Symbol(x, Decl(index.ts, 6, 5)) +>PkgType : Symbol(PkgType, Decl(index.ts, 3, 13)) +>esm : Symbol(esm, Decl(index.ts, 6, 20)) + +=== /node_modules/pkg/esm.d.mts === +// This file should be resolved when using bundler resolution with "import" condition +export interface PkgType { +>PkgType : Symbol(PkgType, Decl(esm.d.mts, 0, 0)) + + esm: true; +>esm : Symbol(PkgType.esm, Decl(esm.d.mts, 1, 26)) +} +declare global { +>global : Symbol(global, Decl(esm.d.mts, 3, 1)) + + var expectedCondition: "import"; +>expectedCondition : Symbol(expectedCondition, Decl(esm.d.mts, 5, 7)) +} + diff --git a/testdata/baselines/reference/compiler/automaticTypeDirectiveResolutionBundler.trace.json b/testdata/baselines/reference/compiler/automaticTypeDirectiveResolutionBundler.trace.json new file mode 100644 index 00000000000..87041e80987 --- /dev/null +++ b/testdata/baselines/reference/compiler/automaticTypeDirectiveResolutionBundler.trace.json @@ -0,0 +1,42 @@ +======== Resolving module 'pkg' from '/index.ts'. ======== +Explicitly specified module resolution kind: 'Bundler'. +Resolving in CJS mode with conditions 'import', 'types'. +File '/package.json' does not exist. +Loading module 'pkg' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration, JSON. +Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration. +Found 'package.json' at '/node_modules/pkg/package.json'. +Entering conditional exports. +Matched 'exports' condition 'import'. +Entering conditional exports. +Matched 'exports' condition 'types'. +Using 'exports' subpath '.' with target './esm.d.mts'. +File '/node_modules/pkg/esm.d.mts' exists - use it as a name resolution result. +'package.json' does not have a 'peerDependencies' field. +Resolved under condition 'types'. +Exiting conditional exports. +Resolved under condition 'import'. +Exiting conditional exports. +Resolving real path for '/node_modules/pkg/esm.d.mts', result '/node_modules/pkg/esm.d.mts'. +======== Module name 'pkg' was successfully resolved to '/node_modules/pkg/esm.d.mts' with Package ID 'pkg/esm.d.mts@1.0.0'. ======== +======== Resolving type reference directive 'pkg', containing file '/.src/__inferred type names__.ts', root directory '/.src/node_modules/@types,/node_modules/@types'. ======== +Resolving with primary search path '/.src/node_modules/@types, /node_modules/@types'. +Directory '/.src/node_modules/@types' does not exist, skipping all lookups in it. +Directory '/node_modules/@types' does not exist, skipping all lookups in it. +Looking up in 'node_modules' folder, initial location '/.src'. +Searching all ancestor node_modules directories for preferred extensions: Declaration. +Directory '/.src/node_modules' does not exist, skipping all lookups in it. +Directory '/.src/node_modules/@types' does not exist, skipping all lookups in it. +File '/node_modules/pkg/package.json' exists according to earlier cached lookups. +Entering conditional exports. +Matched 'exports' condition 'import'. +Entering conditional exports. +Matched 'exports' condition 'types'. +Using 'exports' subpath '.' with target './esm.d.mts'. +File '/node_modules/pkg/esm.d.mts' exists - use it as a name resolution result. +'package.json' does not have a 'peerDependencies' field. +Resolved under condition 'types'. +Exiting conditional exports. +Resolved under condition 'import'. +Exiting conditional exports. +Resolving real path for '/node_modules/pkg/esm.d.mts', result '/node_modules/pkg/esm.d.mts'. +======== Type reference directive 'pkg' was successfully resolved to '/node_modules/pkg/esm.d.mts' with Package ID 'pkg/esm.d.mts@1.0.0', primary: false. ======== diff --git a/testdata/baselines/reference/compiler/automaticTypeDirectiveResolutionBundler.types b/testdata/baselines/reference/compiler/automaticTypeDirectiveResolutionBundler.types new file mode 100644 index 00000000000..1f071869feb --- /dev/null +++ b/testdata/baselines/reference/compiler/automaticTypeDirectiveResolutionBundler.types @@ -0,0 +1,30 @@ +//// [tests/cases/compiler/automaticTypeDirectiveResolutionBundler.ts] //// + +=== /index.ts === +// The automatic type directive "pkg" from @types should resolve to esm.d.mts +// because bundler resolution uses the "import" condition. +// If the wrong file is resolved, we'll get a type error due to conflicting declarations. +import type { PkgType } from "pkg"; +>PkgType : PkgType + +// This should work if esm.d.mts is correctly resolved +const x: PkgType = { esm: true }; +>x : PkgType +>{ esm: true } : { esm: true; } +>esm : true +>true : true + +=== /node_modules/pkg/esm.d.mts === +// This file should be resolved when using bundler resolution with "import" condition +export interface PkgType { + esm: true; +>esm : true +>true : true +} +declare global { +>global : typeof global + + var expectedCondition: "import"; +>expectedCondition : "import" +} + diff --git a/testdata/tests/cases/compiler/automaticTypeDirectiveResolutionBundler.ts b/testdata/tests/cases/compiler/automaticTypeDirectiveResolutionBundler.ts new file mode 100644 index 00000000000..57b13ff5a96 --- /dev/null +++ b/testdata/tests/cases/compiler/automaticTypeDirectiveResolutionBundler.ts @@ -0,0 +1,50 @@ +// @noImplicitReferences: true +// @module: esnext +// @moduleResolution: bundler +// @types: pkg +// @traceResolution: true +// @noEmit: true +// @strict: true + +// @filename: /node_modules/pkg/package.json +{ + "name": "pkg", + "version": "1.0.0", + "exports": { + ".": { + "import": { + "types": "./esm.d.mts" + }, + "default": { + "types": "./cjs.d.ts" + } + } + } +} + +// @filename: /node_modules/pkg/esm.d.mts +// This file should be resolved when using bundler resolution with "import" condition +export interface PkgType { + esm: true; +} +declare global { + var expectedCondition: "import"; +} + +// @filename: /node_modules/pkg/cjs.d.ts +// This file should NOT be resolved - it's the "default" condition fallback +export interface PkgType { + cjs: true; // Different shape - will cause error if wrong file is used +} +declare global { + var expectedCondition: "default"; // Conflicts with esm.d.mts if both are loaded +} + +// @filename: /index.ts +// The automatic type directive "pkg" from @types should resolve to esm.d.mts +// because bundler resolution uses the "import" condition. +// If the wrong file is resolved, we'll get a type error due to conflicting declarations. +import type { PkgType } from "pkg"; + +// This should work if esm.d.mts is correctly resolved +const x: PkgType = { esm: true };