diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c5701087ebfd4..235196ef727fc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -51050,6 +51050,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker) { const type = getTypeOfSymbol(getSymbolOfDeclaration(node)); + + // Check if we're in a namespace declaration - in this case we need fully qualified enum references + let enclosingNode: Node | undefined = node; + let useFullyQualified = false; + + if (isVariableDeclaration(node) && type.flags & TypeFlags.EnumLike) { + const parentStatement = node.parent?.parent; // VariableDeclaration -> VariableDeclarationList -> VariableStatement + const moduleBlock = parentStatement?.parent; // VariableStatement -> ModuleBlock + const moduleDeclaration = moduleBlock?.parent; // ModuleBlock -> ModuleDeclaration + if (moduleDeclaration && isModuleDeclaration(moduleDeclaration)) { + // We're in a namespace - use fully qualified references for enum constants + useFullyQualified = true; + enclosingNode = undefined; + } + } + + // For enum types, use the nodeBuilder to get properly qualified references + if (type.flags & TypeFlags.EnumLike) { + const enumExpression = nodeBuilder.symbolToExpression( + type.symbol, + SymbolFlags.Value, + enclosingNode, + useFullyQualified ? NodeBuilderFlags.UseFullyQualifiedType : undefined, + /*internalFlags*/ undefined, + tracker, + ); + if (enumExpression) return enumExpression; + } + return literalTypeToNode(type as FreshableType, node, tracker); } diff --git a/tests/baselines/reference/enumNamespaceConstantsDeclaration.js b/tests/baselines/reference/enumNamespaceConstantsDeclaration.js new file mode 100644 index 0000000000000..491a04e6baa64 --- /dev/null +++ b/tests/baselines/reference/enumNamespaceConstantsDeclaration.js @@ -0,0 +1,59 @@ +//// [tests/cases/compiler/enumNamespaceConstantsDeclaration.ts] //// + +//// [enumNamespaceConstantsDeclaration.ts] +// Test for constant declarations inside namespace merged with enum +enum Foo { + bar +} +namespace Foo { + export const baz = Foo.bar; +} + +// Multiple enum members +enum MyEnum { + First = 1, + Second = 2 +} +namespace MyEnum { + export const value1 = MyEnum.First; + export const value2 = MyEnum.Second; +} + + + +//// [enumNamespaceConstantsDeclaration.js] +// Test for constant declarations inside namespace merged with enum +var Foo; +(function (Foo) { + Foo[Foo["bar"] = 0] = "bar"; +})(Foo || (Foo = {})); +(function (Foo) { + Foo.baz = Foo.bar; +})(Foo || (Foo = {})); +// Multiple enum members +var MyEnum; +(function (MyEnum) { + MyEnum[MyEnum["First"] = 1] = "First"; + MyEnum[MyEnum["Second"] = 2] = "Second"; +})(MyEnum || (MyEnum = {})); +(function (MyEnum) { + MyEnum.value1 = MyEnum.First; + MyEnum.value2 = MyEnum.Second; +})(MyEnum || (MyEnum = {})); + + +//// [enumNamespaceConstantsDeclaration.d.ts] +declare enum Foo { + bar = 0 +} +declare namespace Foo { + const baz = Foo.bar; +} +declare enum MyEnum { + First = 1, + Second = 2 +} +declare namespace MyEnum { + const value1 = MyEnum.First; + const value2 = MyEnum.Second; +} diff --git a/tests/baselines/reference/enumNamespaceConstantsDeclaration.symbols b/tests/baselines/reference/enumNamespaceConstantsDeclaration.symbols new file mode 100644 index 0000000000000..75251bd0d1dc9 --- /dev/null +++ b/tests/baselines/reference/enumNamespaceConstantsDeclaration.symbols @@ -0,0 +1,47 @@ +//// [tests/cases/compiler/enumNamespaceConstantsDeclaration.ts] //// + +=== enumNamespaceConstantsDeclaration.ts === +// Test for constant declarations inside namespace merged with enum +enum Foo { +>Foo : Symbol(Foo, Decl(enumNamespaceConstantsDeclaration.ts, 0, 0), Decl(enumNamespaceConstantsDeclaration.ts, 3, 1)) + + bar +>bar : Symbol(Foo.bar, Decl(enumNamespaceConstantsDeclaration.ts, 1, 10)) +} +namespace Foo { +>Foo : Symbol(Foo, Decl(enumNamespaceConstantsDeclaration.ts, 0, 0), Decl(enumNamespaceConstantsDeclaration.ts, 3, 1)) + + export const baz = Foo.bar; +>baz : Symbol(baz, Decl(enumNamespaceConstantsDeclaration.ts, 5, 16)) +>Foo.bar : Symbol(bar, Decl(enumNamespaceConstantsDeclaration.ts, 1, 10)) +>Foo : Symbol(Foo, Decl(enumNamespaceConstantsDeclaration.ts, 0, 0), Decl(enumNamespaceConstantsDeclaration.ts, 3, 1)) +>bar : Symbol(bar, Decl(enumNamespaceConstantsDeclaration.ts, 1, 10)) +} + +// Multiple enum members +enum MyEnum { +>MyEnum : Symbol(MyEnum, Decl(enumNamespaceConstantsDeclaration.ts, 6, 1), Decl(enumNamespaceConstantsDeclaration.ts, 12, 1)) + + First = 1, +>First : Symbol(MyEnum.First, Decl(enumNamespaceConstantsDeclaration.ts, 9, 13)) + + Second = 2 +>Second : Symbol(MyEnum.Second, Decl(enumNamespaceConstantsDeclaration.ts, 10, 14)) +} +namespace MyEnum { +>MyEnum : Symbol(MyEnum, Decl(enumNamespaceConstantsDeclaration.ts, 6, 1), Decl(enumNamespaceConstantsDeclaration.ts, 12, 1)) + + export const value1 = MyEnum.First; +>value1 : Symbol(value1, Decl(enumNamespaceConstantsDeclaration.ts, 14, 16)) +>MyEnum.First : Symbol(First, Decl(enumNamespaceConstantsDeclaration.ts, 9, 13)) +>MyEnum : Symbol(MyEnum, Decl(enumNamespaceConstantsDeclaration.ts, 6, 1), Decl(enumNamespaceConstantsDeclaration.ts, 12, 1)) +>First : Symbol(First, Decl(enumNamespaceConstantsDeclaration.ts, 9, 13)) + + export const value2 = MyEnum.Second; +>value2 : Symbol(value2, Decl(enumNamespaceConstantsDeclaration.ts, 15, 16)) +>MyEnum.Second : Symbol(Second, Decl(enumNamespaceConstantsDeclaration.ts, 10, 14)) +>MyEnum : Symbol(MyEnum, Decl(enumNamespaceConstantsDeclaration.ts, 6, 1), Decl(enumNamespaceConstantsDeclaration.ts, 12, 1)) +>Second : Symbol(Second, Decl(enumNamespaceConstantsDeclaration.ts, 10, 14)) +} + + diff --git a/tests/baselines/reference/enumNamespaceConstantsDeclaration.types b/tests/baselines/reference/enumNamespaceConstantsDeclaration.types new file mode 100644 index 0000000000000..dcc1651d7415e --- /dev/null +++ b/tests/baselines/reference/enumNamespaceConstantsDeclaration.types @@ -0,0 +1,70 @@ +//// [tests/cases/compiler/enumNamespaceConstantsDeclaration.ts] //// + +=== enumNamespaceConstantsDeclaration.ts === +// Test for constant declarations inside namespace merged with enum +enum Foo { +>Foo : Foo +> : ^^^ + + bar +>bar : Foo.bar +> : ^^^^^^^ +} +namespace Foo { +>Foo : typeof Foo +> : ^^^^^^^^^^ + + export const baz = Foo.bar; +>baz : Foo.bar +> : ^^^^^^^ +>Foo.bar : Foo +> : ^^^ +>Foo : typeof Foo +> : ^^^^^^^^^^ +>bar : Foo +> : ^^^ +} + +// Multiple enum members +enum MyEnum { +>MyEnum : MyEnum +> : ^^^^^^ + + First = 1, +>First : MyEnum.First +> : ^^^^^^^^^^^^ +>1 : 1 +> : ^ + + Second = 2 +>Second : MyEnum.Second +> : ^^^^^^^^^^^^^ +>2 : 2 +> : ^ +} +namespace MyEnum { +>MyEnum : typeof MyEnum +> : ^^^^^^^^^^^^^ + + export const value1 = MyEnum.First; +>value1 : MyEnum.First +> : ^^^^^^^^^^^^ +>MyEnum.First : MyEnum.First +> : ^^^^^^^^^^^^ +>MyEnum : typeof MyEnum +> : ^^^^^^^^^^^^^ +>First : MyEnum.First +> : ^^^^^^^^^^^^ + + export const value2 = MyEnum.Second; +>value2 : MyEnum.Second +> : ^^^^^^^^^^^^^ +>MyEnum.Second : MyEnum.Second +> : ^^^^^^^^^^^^^ +>MyEnum : typeof MyEnum +> : ^^^^^^^^^^^^^ +>Second : MyEnum.Second +> : ^^^^^^^^^^^^^ +} + + diff --git a/tests/cases/compiler/enumNamespaceConstantsDeclaration.ts b/tests/cases/compiler/enumNamespaceConstantsDeclaration.ts new file mode 100644 index 0000000000000..36ed26d25bd10 --- /dev/null +++ b/tests/cases/compiler/enumNamespaceConstantsDeclaration.ts @@ -0,0 +1,20 @@ +// @declaration: true + +// Test for constant declarations inside namespace merged with enum +enum Foo { + bar +} +namespace Foo { + export const baz = Foo.bar; +} + +// Multiple enum members +enum MyEnum { + First = 1, + Second = 2 +} +namespace MyEnum { + export const value1 = MyEnum.First; + export const value2 = MyEnum.Second; +} +