diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 2578ba4c4df..b688e9e1e52 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -40710,7 +40710,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query);
}
- if (getIsolatedModules(compilerOptions)) {
+ // --verbatimModuleSyntax only gets checked here when the enum usage does not
+ // resolve to an import, because imports of ambient const enums get checked
+ // separately in `checkAliasSymbol`.
+ if (
+ compilerOptions.isolatedModules
+ || compilerOptions.verbatimModuleSyntax
+ && ok
+ && !resolveName(
+ node,
+ getFirstIdentifier(node as EntityNameOrEntityNameExpression),
+ SymbolFlags.Alias,
+ /*nameNotFoundMessage*/ undefined,
+ /*isUse*/ false,
+ /*excludeGlobals*/ true,
+ )
+ ) {
Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum));
const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration;
const redirect = host.getRedirectReferenceForResolutionFromSourceOfProject(getSourceFileOfNode(constEnumDeclaration).resolvedPath);
@@ -47264,6 +47279,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// in files that are unambiguously CommonJS in this mode.
error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_module_is_set_to_preserve);
}
+
+ if (
+ compilerOptions.verbatimModuleSyntax &&
+ !isTypeOnlyImportOrExportDeclaration(node) &&
+ !(node.flags & NodeFlags.Ambient) &&
+ targetFlags & SymbolFlags.ConstEnum
+ ) {
+ const constEnumDeclaration = target.valueDeclaration as EnumDeclaration;
+ const redirect = host.getRedirectReferenceForResolutionFromSourceOfProject(getSourceFileOfNode(constEnumDeclaration).resolvedPath);
+ if (constEnumDeclaration.flags & NodeFlags.Ambient && (!redirect || !shouldPreserveConstEnums(redirect.commandLine.options))) {
+ error(node, Diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, isolatedModulesLikeFlagName);
+ }
+ }
}
if (isImportSpecifier(node)) {
diff --git a/src/testRunner/unittests/tsc/projectReferences.ts b/src/testRunner/unittests/tsc/projectReferences.ts
index d1dda68e078..27a575ca02a 100644
--- a/src/testRunner/unittests/tsc/projectReferences.ts
+++ b/src/testRunner/unittests/tsc/projectReferences.ts
@@ -115,4 +115,42 @@ describe("unittests:: tsc:: projectReferences::", () => {
}),
commandLineArgs: ["--p", "src/project"],
});
+
+ verifyTsc({
+ scenario: "projectReferences",
+ subScenario: "importing const enum from referenced project with preserveConstEnums and verbatimModuleSyntax",
+ fs: () =>
+ loadProjectFromFiles({
+ "/src/preserve/index.ts": "export const enum E { A = 1 }",
+ "/src/preserve/index.d.ts": "export declare const enum E { A = 1 }",
+ "/src/preserve/tsconfig.json": jsonToReadableText({
+ compilerOptions: {
+ composite: true,
+ declaration: true,
+ preserveConstEnums: true,
+ },
+ }),
+ "/src/no-preserve/index.ts": "export const enum E { A = 1 }",
+ "/src/no-preserve/index.d.ts": "export declare const enum F { A = 1 }",
+ "/src/no-preserve/tsconfig.json": jsonToReadableText({
+ compilerOptions: {
+ composite: true,
+ declaration: true,
+ preserveConstEnums: false,
+ },
+ }),
+ "/src/project/index.ts": `import { E } from "../preserve";\nimport { F } from "../no-preserve";\nE.A; F.A;`,
+ "/src/project/tsconfig.json": jsonToReadableText({
+ compilerOptions: {
+ module: "preserve",
+ verbatimModuleSyntax: true,
+ },
+ references: [
+ { path: "../preserve" },
+ { path: "../no-preserve" },
+ ],
+ }),
+ }),
+ commandLineArgs: ["--p", "src/project", "--pretty", "false"],
+ });
});
diff --git a/tests/baselines/reference/tsc/projectReferences/importing-const-enum-from-referenced-project-with-preserveConstEnums-and-verbatimModuleSyntax.js b/tests/baselines/reference/tsc/projectReferences/importing-const-enum-from-referenced-project-with-preserveConstEnums-and-verbatimModuleSyntax.js
new file mode 100644
index 00000000000..45a6868c9ec
--- /dev/null
+++ b/tests/baselines/reference/tsc/projectReferences/importing-const-enum-from-referenced-project-with-preserveConstEnums-and-verbatimModuleSyntax.js
@@ -0,0 +1,83 @@
+currentDirectory:: / useCaseSensitiveFileNames: false
+Input::
+//// [/lib/lib.d.ts]
+///
+interface Boolean {}
+interface Function {}
+interface CallableFunction {}
+interface NewableFunction {}
+interface IArguments {}
+interface Number { toExponential: any; }
+interface Object {}
+interface RegExp {}
+interface String { charAt: any; }
+interface Array { length: number; [n: number]: T; }
+interface ReadonlyArray {}
+declare const console: { log(msg: any): void; };
+
+//// [/src/no-preserve/index.d.ts]
+export declare const enum F { A = 1 }
+
+//// [/src/no-preserve/index.ts]
+export const enum E { A = 1 }
+
+//// [/src/no-preserve/tsconfig.json]
+{
+ "compilerOptions": {
+ "composite": true,
+ "declaration": true,
+ "preserveConstEnums": false
+ }
+}
+
+//// [/src/preserve/index.d.ts]
+export declare const enum E { A = 1 }
+
+//// [/src/preserve/index.ts]
+export const enum E { A = 1 }
+
+//// [/src/preserve/tsconfig.json]
+{
+ "compilerOptions": {
+ "composite": true,
+ "declaration": true,
+ "preserveConstEnums": true
+ }
+}
+
+//// [/src/project/index.ts]
+import { E } from "../preserve";
+import { F } from "../no-preserve";
+E.A; F.A;
+
+//// [/src/project/tsconfig.json]
+{
+ "compilerOptions": {
+ "module": "preserve",
+ "verbatimModuleSyntax": true
+ },
+ "references": [
+ {
+ "path": "../preserve"
+ },
+ {
+ "path": "../no-preserve"
+ }
+ ]
+}
+
+
+
+Output::
+/lib/tsc --p src/project --pretty false
+src/project/index.ts(2,10): error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
+exitCode:: ExitStatus.DiagnosticsPresent_OutputsGenerated
+
+
+//// [/src/project/index.js]
+import { E } from "../preserve";
+import { F } from "../no-preserve";
+E.A;
+F.A;
+
+
diff --git a/tests/baselines/reference/verbatimModuleSyntaxAmbientConstEnum.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxAmbientConstEnum.errors.txt
new file mode 100644
index 00000000000..e405f0bed9c
--- /dev/null
+++ b/tests/baselines/reference/verbatimModuleSyntaxAmbientConstEnum.errors.txt
@@ -0,0 +1,27 @@
+/a.ts(1,10): error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
+/a.ts(4,1): error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
+/b.ts(1,10): error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
+
+
+==== /node_modules/pkg/index.d.ts (0 errors) ====
+ export declare const enum E { A, B, C }
+ declare global {
+ const enum F { A, B, C }
+ }
+
+==== /a.ts (2 errors) ====
+ import { E } from "pkg"; // Error
+ ~
+!!! error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
+ import type { E as _E } from "pkg"; // Ok
+ console.log(E.A); // Ok
+ F.A; // Error
+ ~
+!!! error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
+
+==== /b.ts (1 errors) ====
+ export { E } from "pkg"; // Error
+ ~
+!!! error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled.
+ export type { E as _E } from "pkg"; // Ok
+
\ No newline at end of file
diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxAmbientConstEnum.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxAmbientConstEnum.ts
new file mode 100644
index 00000000000..d59dbadf5d6
--- /dev/null
+++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxAmbientConstEnum.ts
@@ -0,0 +1,21 @@
+// @verbatimModuleSyntax: true
+// @target: esnext
+// @module: preserve
+// @noEmit: true
+// @noTypesAndSymbols: true
+
+// @Filename: /node_modules/pkg/index.d.ts
+export declare const enum E { A, B, C }
+declare global {
+ const enum F { A, B, C }
+}
+
+// @Filename: /a.ts
+import { E } from "pkg"; // Error
+import type { E as _E } from "pkg"; // Ok
+console.log(E.A); // Ok
+F.A; // Error
+
+// @Filename: /b.ts
+export { E } from "pkg"; // Error
+export type { E as _E } from "pkg"; // Ok