From b821480bf247cad94d09768d9920397a1767b158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 20 Oct 2026 14:59:22 +0200 Subject: [PATCH 1/2] Cover pattern ambient module precedence for resolved files --- ...mbientModuleResolvedEmptyModule.errors.txt | 61 +++++++++++++++++++ ...ternAmbientModuleResolvedScript.errors.txt | 50 +++++++++++++++ ...oduleResolvedScriptWithoutPaths.errors.txt | 49 +++++++++++++++ ...patternAmbientModuleResolvedEmptyModule.ts | 52 ++++++++++++++++ .../patternAmbientModuleResolvedScript.ts | 50 +++++++++++++++ ...AmbientModuleResolvedScriptWithoutPaths.ts | 49 +++++++++++++++ 6 files changed, 311 insertions(+) create mode 100644 tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedEmptyModule.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScript.errors.txt create mode 100644 tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScriptWithoutPaths.errors.txt create mode 100644 tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedEmptyModule.ts create mode 100644 tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedScript.ts create mode 100644 tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedScriptWithoutPaths.ts diff --git a/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedEmptyModule.errors.txt b/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedEmptyModule.errors.txt new file mode 100644 index 0000000000000..f5c57582a5fbf --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedEmptyModule.errors.txt @@ -0,0 +1,61 @@ +/src/main.ts(4,8): error TS1192: Module '"/src/script"' has no default export. +/src/main.ts(5,7): error TS2322: Type 'typeof import("/stub")' is not assignable to type 'number'. +/src/main.ts(6,7): error TS2322: Type 'typeof import("/stub")' is not assignable to type 'number'. +/src/main.ts(7,7): error TS2322: Type 'typeof import("/generated/component.svelte")' is not assignable to type 'number'. + + +==== /tsconfig.json (0 errors) ==== + { + "compilerOptions": { + "paths": { "x.svelte": ["./stub.d.ts"] }, + "rootDirs": ["./src", "./generated"] + }, + "files": ["ambient.d.ts", "src/main.ts"] + } + +==== /ambient.d.ts (0 errors) ==== + declare module "*.svelte" { + const value: number; + export default value; + } + declare module "*.svelte" with { type: "text" } { + const value: string; + export default value; + } + declare module "*.js" { + const value: number; + export default value; + } + +==== /src/main.ts (4 errors) ==== + import fromPaths from "x.svelte"; + import emptyAttributes from "x.svelte" with {}; + import fromRootDirs from "./component.svelte"; + import fromRelative from "./script.js"; + ~~~~~~~~~~~~ +!!! error TS1192: Module '"/src/script"' has no default export. + const fromPathsValue: number = fromPaths; + ~~~~~~~~~~~~~~ +!!! error TS2322: Type 'typeof import("/stub")' is not assignable to type 'number'. + const emptyAttributesValue: number = emptyAttributes; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'typeof import("/stub")' is not assignable to type 'number'. + const fromRootDirsValue: number = fromRootDirs; + ~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type 'typeof import("/generated/component.svelte")' is not assignable to type 'number'. + + import text from "x.svelte" with { type: "text" }; + const textValue: string = text; + + import missing from "./missing.svelte"; + const missingValue: number = missing; + +==== /stub.d.ts (0 errors) ==== + export {}; + +==== /generated/component.svelte.d.ts (0 errors) ==== + export {}; + +==== /src/script.ts (0 errors) ==== + export {}; + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScript.errors.txt b/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScript.errors.txt new file mode 100644 index 0000000000000..332fdeddd69c5 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScript.errors.txt @@ -0,0 +1,50 @@ +/src/main.ts(5,7): error TS2322: Type 'number' is not assignable to type 'string'. + + +==== /tsconfig.json (0 errors) ==== + { + "compilerOptions": { + "paths": { "x.svelte": ["./stub.d.ts"] }, + "rootDirs": ["./src", "./generated"] + }, + "files": ["ambient.d.ts", "src/main.ts"] + } + +==== /ambient.d.ts (0 errors) ==== + declare module "*.svelte" { + const value: number; + export default value; + } + declare module "*.svelte" with { type: "text" } { + const value: string; + export default value; + } + declare module "*.js" { + const value: number; + export default value; + } + +==== /src/main.ts (1 errors) ==== + import fromPaths from "x.svelte"; + import emptyAttributes from "x.svelte" with {}; + import fromRootDirs from "./component.svelte"; + import fromRelative from "./script.js"; + const fromPathsValue: string = fromPaths; + ~~~~~~~~~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + import text from "x.svelte" with { type: "text" }; + const textValue: string = text; + + import missing from "./missing.svelte"; + const missingValue: number = missing; + +==== /stub.d.ts (0 errors) ==== + // A resolved script must not fall back to a pattern ambient module without attributes. + +==== /generated/component.svelte.d.ts (0 errors) ==== + // A script resolved through rootDirs. + +==== /src/script.ts (0 errors) ==== + // A script resolved through a relative import. + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScriptWithoutPaths.errors.txt b/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScriptWithoutPaths.errors.txt new file mode 100644 index 0000000000000..c0c3447af94bf --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScriptWithoutPaths.errors.txt @@ -0,0 +1,49 @@ +/src/main.ts(5,7): error TS2322: Type 'number' is not assignable to type 'string'. + + +==== /tsconfig.json (0 errors) ==== + { + "compilerOptions": { + "rootDirs": ["./src", "./generated"] + }, + "files": ["ambient.d.ts", "src/main.ts"] + } + +==== /ambient.d.ts (0 errors) ==== + declare module "*.svelte" { + const value: number; + export default value; + } + declare module "*.svelte" with { type: "text" } { + const value: string; + export default value; + } + declare module "*.js" { + const value: number; + export default value; + } + +==== /src/main.ts (1 errors) ==== + import fromPaths from "x.svelte"; + import emptyAttributes from "x.svelte" with {}; + import fromRootDirs from "./component.svelte"; + import fromRelative from "./script.js"; + const fromPathsValue: string = fromPaths; + ~~~~~~~~~~~~~~ +!!! error TS2322: Type 'number' is not assignable to type 'string'. + + import text from "x.svelte" with { type: "text" }; + const textValue: string = text; + + import missing from "./missing.svelte"; + const missingValue: number = missing; + +==== /stub.d.ts (0 errors) ==== + // This file is not resolved without a paths mapping. + +==== /generated/component.svelte.d.ts (0 errors) ==== + // A script resolved through rootDirs. + +==== /src/script.ts (0 errors) ==== + // A script resolved through a relative import. + \ No newline at end of file diff --git a/tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedEmptyModule.ts b/tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedEmptyModule.ts new file mode 100644 index 0000000000000..b7c9cbc02c495 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedEmptyModule.ts @@ -0,0 +1,52 @@ +// @strict: true +// @module: esnext +// @moduleResolution: bundler +// @noEmit: true +// @noTypesAndSymbols: true + +// @filename: /tsconfig.json +{ + "compilerOptions": { + "paths": { "x.svelte": ["./stub.d.ts"] }, + "rootDirs": ["./src", "./generated"] + }, + "files": ["ambient.d.ts", "src/main.ts"] +} + +// @filename: /ambient.d.ts +declare module "*.svelte" { + const value: number; + export default value; +} +declare module "*.svelte" with { type: "text" } { + const value: string; + export default value; +} +declare module "*.js" { + const value: number; + export default value; +} + +// @filename: /stub.d.ts +export {}; + +// @filename: /generated/component.svelte.d.ts +export {}; + +// @filename: /src/script.ts +export {}; + +// @filename: /src/main.ts +import fromPaths from "x.svelte"; +import emptyAttributes from "x.svelte" with {}; +import fromRootDirs from "./component.svelte"; +import fromRelative from "./script.js"; +const fromPathsValue: number = fromPaths; +const emptyAttributesValue: number = emptyAttributes; +const fromRootDirsValue: number = fromRootDirs; + +import text from "x.svelte" with { type: "text" }; +const textValue: string = text; + +import missing from "./missing.svelte"; +const missingValue: number = missing; diff --git a/tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedScript.ts b/tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedScript.ts new file mode 100644 index 0000000000000..782e943c07625 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedScript.ts @@ -0,0 +1,50 @@ +// @strict: true +// @module: esnext +// @moduleResolution: bundler +// @noEmit: true +// @noTypesAndSymbols: true + +// @filename: /tsconfig.json +{ + "compilerOptions": { + "paths": { "x.svelte": ["./stub.d.ts"] }, + "rootDirs": ["./src", "./generated"] + }, + "files": ["ambient.d.ts", "src/main.ts"] +} + +// @filename: /ambient.d.ts +declare module "*.svelte" { + const value: number; + export default value; +} +declare module "*.svelte" with { type: "text" } { + const value: string; + export default value; +} +declare module "*.js" { + const value: number; + export default value; +} + +// @filename: /stub.d.ts +// A resolved script must not fall back to a pattern ambient module without attributes. + +// @filename: /generated/component.svelte.d.ts +// A script resolved through rootDirs. + +// @filename: /src/script.ts +// A script resolved through a relative import. + +// @filename: /src/main.ts +import fromPaths from "x.svelte"; +import emptyAttributes from "x.svelte" with {}; +import fromRootDirs from "./component.svelte"; +import fromRelative from "./script.js"; +const fromPathsValue: string = fromPaths; + +import text from "x.svelte" with { type: "text" }; +const textValue: string = text; + +import missing from "./missing.svelte"; +const missingValue: number = missing; diff --git a/tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedScriptWithoutPaths.ts b/tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedScriptWithoutPaths.ts new file mode 100644 index 0000000000000..232d40cd9f3e8 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/patternAmbientModuleResolvedScriptWithoutPaths.ts @@ -0,0 +1,49 @@ +// @strict: true +// @module: esnext +// @moduleResolution: bundler +// @noEmit: true +// @noTypesAndSymbols: true + +// @filename: /tsconfig.json +{ + "compilerOptions": { + "rootDirs": ["./src", "./generated"] + }, + "files": ["ambient.d.ts", "src/main.ts"] +} + +// @filename: /ambient.d.ts +declare module "*.svelte" { + const value: number; + export default value; +} +declare module "*.svelte" with { type: "text" } { + const value: string; + export default value; +} +declare module "*.js" { + const value: number; + export default value; +} + +// @filename: /stub.d.ts +// This file is not resolved without a paths mapping. + +// @filename: /generated/component.svelte.d.ts +// A script resolved through rootDirs. + +// @filename: /src/script.ts +// A script resolved through a relative import. + +// @filename: /src/main.ts +import fromPaths from "x.svelte"; +import emptyAttributes from "x.svelte" with {}; +import fromRootDirs from "./component.svelte"; +import fromRelative from "./script.js"; +const fromPathsValue: string = fromPaths; + +import text from "x.svelte" with { type: "text" }; +const textValue: string = text; + +import missing from "./missing.svelte"; +const missingValue: number = missing; From c2d9aab40929a0d8f9537413bd0bba10a2dab1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 20 Oct 2026 14:59:46 +0200 Subject: [PATCH 2/2] Preserve non-module errors for imports without attributes --- tsc/internal/checker/checker.go | 8 +++++--- ...atternAmbientModuleResolvedScript.errors.txt | 17 +++++++++++++---- ...tModuleResolvedScriptWithoutPaths.errors.txt | 8 +++++++- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 10ddb3c0c88b4..73250c46b97e4 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -15695,9 +15695,11 @@ func (c *Checker) resolveExternalModule( } return c.tryResolvePatternAmbientModule(c.getMergedSymbol(sourceFile.Symbol), moduleReference, importAttributesType) } - patternAmbientModule := c.tryResolvePatternAmbientModule(nil /*resolvedSymbol*/, moduleReference, importAttributesType) - if patternAmbientModule != nil { - return patternAmbientModule + if !c.isEmptyObjectType(importAttributesType) { + patternAmbientModule := c.tryResolvePatternAmbientModule(nil /*resolvedSymbol*/, moduleReference, importAttributesType) + if patternAmbientModule != nil { + return patternAmbientModule + } } if errorNode != nil && moduleNotFoundError != nil && !isSideEffectImport(errorNode) { c.error(errorNode, diagnostics.File_0_is_not_a_module, resolvedModule.ResolvedFileName) diff --git a/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScript.errors.txt b/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScript.errors.txt index 332fdeddd69c5..4720210c86ed8 100644 --- a/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScript.errors.txt +++ b/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScript.errors.txt @@ -1,4 +1,7 @@ -/src/main.ts(5,7): error TS2322: Type 'number' is not assignable to type 'string'. +/src/main.ts(1,23): error TS2306: File '/stub.d.ts' is not a module. +/src/main.ts(2,29): error TS2306: File '/stub.d.ts' is not a module. +/src/main.ts(3,26): error TS2306: File '/generated/component.svelte.d.ts' is not a module. +/src/main.ts(4,26): error TS2306: File '/src/script.ts' is not a module. ==== /tsconfig.json (0 errors) ==== @@ -24,14 +27,20 @@ export default value; } -==== /src/main.ts (1 errors) ==== +==== /src/main.ts (4 errors) ==== import fromPaths from "x.svelte"; + ~~~~~~~~~~ +!!! error TS2306: File '/stub.d.ts' is not a module. import emptyAttributes from "x.svelte" with {}; + ~~~~~~~~~~ +!!! error TS2306: File '/stub.d.ts' is not a module. import fromRootDirs from "./component.svelte"; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2306: File '/generated/component.svelte.d.ts' is not a module. import fromRelative from "./script.js"; + ~~~~~~~~~~~~~ +!!! error TS2306: File '/src/script.ts' is not a module. const fromPathsValue: string = fromPaths; - ~~~~~~~~~~~~~~ -!!! error TS2322: Type 'number' is not assignable to type 'string'. import text from "x.svelte" with { type: "text" }; const textValue: string = text; diff --git a/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScriptWithoutPaths.errors.txt b/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScriptWithoutPaths.errors.txt index c0c3447af94bf..8e40142d4812e 100644 --- a/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScriptWithoutPaths.errors.txt +++ b/tsc/testdata/baselines/reference/compiler/patternAmbientModuleResolvedScriptWithoutPaths.errors.txt @@ -1,3 +1,5 @@ +/src/main.ts(3,26): error TS2306: File '/generated/component.svelte.d.ts' is not a module. +/src/main.ts(4,26): error TS2306: File '/src/script.ts' is not a module. /src/main.ts(5,7): error TS2322: Type 'number' is not assignable to type 'string'. @@ -23,11 +25,15 @@ export default value; } -==== /src/main.ts (1 errors) ==== +==== /src/main.ts (3 errors) ==== import fromPaths from "x.svelte"; import emptyAttributes from "x.svelte" with {}; import fromRootDirs from "./component.svelte"; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS2306: File '/generated/component.svelte.d.ts' is not a module. import fromRelative from "./script.js"; + ~~~~~~~~~~~~~ +!!! error TS2306: File '/src/script.ts' is not a module. const fromPathsValue: string = fromPaths; ~~~~~~~~~~~~~~ !!! error TS2322: Type 'number' is not assignable to type 'string'.