Skip to content

Commit eed9db5

Browse files
Merge pull request #28465 from alangpierce/enforce-const-enum-access-for-isolatedmodules
Change isolatedModules to allow const enum declaration and disallow access
2 parents 12edac0 + 942b020 commit eed9db5

7 files changed

+47
-31
lines changed

src/compiler/checker.ts

+25-17
Original file line numberDiff line numberDiff line change
@@ -23289,22 +23289,34 @@ namespace ts {
2328923289
const uninstantiatedType = checkExpressionWorker(node, checkMode, forceTuple);
2329023290
const type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
2329123291
if (isConstEnumObjectType(type)) {
23292-
// enum object type for const enums are only permitted in:
23293-
// - 'left' in property access
23294-
// - 'object' in indexed access
23295-
// - target in rhs of import statement
23296-
const ok =
23297-
(node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).expression === node) ||
23298-
(node.parent.kind === SyntaxKind.ElementAccessExpression && (<ElementAccessExpression>node.parent).expression === node) ||
23299-
((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(<Identifier>node) ||
23292+
checkConstEnumAccess(node, type);
23293+
}
23294+
currentNode = saveCurrentNode;
23295+
return type;
23296+
}
23297+
23298+
function checkConstEnumAccess(node: Expression | QualifiedName, type: Type) {
23299+
// enum object type for const enums are only permitted in:
23300+
// - 'left' in property access
23301+
// - 'object' in indexed access
23302+
// - target in rhs of import statement
23303+
const ok =
23304+
(node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).expression === node) ||
23305+
(node.parent.kind === SyntaxKind.ElementAccessExpression && (<ElementAccessExpression>node.parent).expression === node) ||
23306+
((node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) && isInRightSideOfImportOrExportAssignment(<Identifier>node) ||
2330023307
(node.parent.kind === SyntaxKind.TypeQuery && (<TypeQueryNode>node.parent).exprName === node));
2330123308

23302-
if (!ok) {
23303-
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);
23309+
if (!ok) {
23310+
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);
23311+
}
23312+
23313+
if (compilerOptions.isolatedModules) {
23314+
Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum));
23315+
const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration;
23316+
if (constEnumDeclaration.flags & NodeFlags.Ambient) {
23317+
error(node, Diagnostics.Cannot_access_ambient_const_enums_when_the_isolatedModules_flag_is_provided);
2330423318
}
2330523319
}
23306-
currentNode = saveCurrentNode;
23307-
return type;
2330823320
}
2330923321

2331023322
function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type {
@@ -27484,11 +27496,6 @@ namespace ts {
2748427496

2748527497
computeEnumMemberValues(node);
2748627498

27487-
const enumIsConst = isEnumConst(node);
27488-
if (compilerOptions.isolatedModules && enumIsConst && node.flags & NodeFlags.Ambient) {
27489-
error(node.name, Diagnostics.Ambient_const_enums_are_not_allowed_when_the_isolatedModules_flag_is_provided);
27490-
}
27491-
2749227499
// Spec 2014 - Section 9.3:
2749327500
// It isn't possible for one enum declaration to continue the automatic numbering sequence of another,
2749427501
// and when an enum type has multiple declarations, only one declaration is permitted to omit a value
@@ -27499,6 +27506,7 @@ namespace ts {
2749927506
const firstDeclaration = getDeclarationOfKind(enumSymbol, node.kind);
2750027507
if (node === firstDeclaration) {
2750127508
if (enumSymbol.declarations.length > 1) {
27509+
const enumIsConst = isEnumConst(node);
2750227510
// check that const is placed\omitted on all enum declarations
2750327511
forEach(enumSymbol.declarations, decl => {
2750427512
if (isEnumDeclaration(decl) && isEnumConst(decl) !== enumIsConst) {

src/compiler/diagnosticMessages.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -659,10 +659,6 @@
659659
"category": "Error",
660660
"code": 1208
661661
},
662-
"Ambient const enums are not allowed when the '--isolatedModules' flag is provided.": {
663-
"category": "Error",
664-
"code": 1209
665-
},
666662
"Invalid use of '{0}'. Class definitions are automatically in strict mode.": {
667663
"category": "Error",
668664
"code": 1210
@@ -2581,6 +2577,10 @@
25812577
"category": "Error",
25822578
"code": 2747
25832579
},
2580+
"Cannot access ambient const enums when the '--isolatedModules' flag is provided.": {
2581+
"category": "Error",
2582+
"code": 2748
2583+
},
25842584

25852585
"Import declaration '{0}' is using private name '{1}'.": {
25862586
"category": "Error",
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
tests/cases/compiler/file1.ts(1,20): error TS1209: Ambient const enums are not allowed when the '--isolatedModules' flag is provided.
1+
tests/cases/compiler/file1.ts(2,16): error TS2748: Cannot access ambient const enums when the '--isolatedModules' flag is provided.
22

33

44
==== tests/cases/compiler/file1.ts (1 errors) ====
55
declare const enum E { X = 1}
6-
~
7-
!!! error TS1209: Ambient const enums are not allowed when the '--isolatedModules' flag is provided.
8-
export var y;
6+
export var y = E.X;
7+
~
8+
!!! error TS2748: Cannot access ambient const enums when the '--isolatedModules' flag is provided.
9+
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//// [file1.ts]
22
declare const enum E { X = 1}
3-
export var y;
3+
export var y = E.X;
4+
45

56
//// [file1.js]
6-
export var y;
7+
export var y = E.X;

tests/baselines/reference/isolatedModulesAmbientConstEnum.symbols

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ declare const enum E { X = 1}
33
>E : Symbol(E, Decl(file1.ts, 0, 0))
44
>X : Symbol(E.X, Decl(file1.ts, 0, 22))
55

6-
export var y;
6+
export var y = E.X;
77
>y : Symbol(y, Decl(file1.ts, 1, 10))
8+
>E.X : Symbol(E.X, Decl(file1.ts, 0, 22))
9+
>E : Symbol(E, Decl(file1.ts, 0, 0))
10+
>X : Symbol(E.X, Decl(file1.ts, 0, 22))
811

tests/baselines/reference/isolatedModulesAmbientConstEnum.types

+5-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ declare const enum E { X = 1}
44
>X : E.X
55
>1 : 1
66

7-
export var y;
8-
>y : any
7+
export var y = E.X;
8+
>y : E
9+
>E.X : E
10+
>E : typeof E
11+
>X : E
912

tests/cases/compiler/isolatedModulesAmbientConstEnum.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
// @filename: file1.ts
55

66
declare const enum E { X = 1}
7-
export var y;
7+
export var y = E.X;

0 commit comments

Comments
 (0)