mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-07-04 14:56:16 -05:00
Fix enum namespace constants declaration generation
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
This commit is contained in:
@@ -50963,7 +50963,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function literalTypeToNode(type: FreshableType, enclosing: Node, tracker: SymbolTracker): Expression {
|
||||
const enumResult = type.flags & TypeFlags.EnumLike ? nodeBuilder.symbolToExpression(type.symbol, SymbolFlags.Value, enclosing, /*flags*/ undefined, /*internalFlags*/ undefined, tracker)
|
||||
const enumResult = type.flags & TypeFlags.EnumLike ? nodeBuilder.symbolToExpression(type.symbol, SymbolFlags.Value, /*enclosing*/ undefined, NodeBuilderFlags.UseFullyQualifiedType, /*internalFlags*/ undefined, tracker)
|
||||
: type === trueType ? factory.createTrue() : type === falseType && factory.createFalse();
|
||||
if (enumResult) return enumResult;
|
||||
const literalValue = (type as LiteralType).value;
|
||||
|
||||
@@ -657,22 +657,9 @@ export function transformDeclarations(context: TransformationContext): Transform
|
||||
}
|
||||
|
||||
function shouldPrintWithInitializer(node: Node): node is CanHaveLiteralInitializer & { initializer: Expression; } {
|
||||
if (!canHaveLiteralInitializer(node) || !node.initializer || !resolver.isLiteralConstDeclaration(getParseTreeNode(node) as CanHaveLiteralInitializer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the initializer is a property access to an enum member (e.g., Foo.bar)
|
||||
// In this case, don't print with initializer - let it get a type annotation instead
|
||||
const unwrappedInitializer = unwrapParenthesizedExpression(node.initializer);
|
||||
if (isPropertyAccessExpression(unwrappedInitializer)) {
|
||||
const constantValue = resolver.getConstantValue(unwrappedInitializer);
|
||||
// If it has a constant value (meaning it's an enum member reference), use type instead of initializer
|
||||
if (constantValue !== undefined) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return canHaveLiteralInitializer(node)
|
||||
&& !!node.initializer
|
||||
&& resolver.isLiteralConstDeclaration(getParseTreeNode(node) as CanHaveLiteralInitializer); // TODO: Make safea
|
||||
}
|
||||
|
||||
function ensureNoInitializer(node: CanHaveLiteralInitializer) {
|
||||
@@ -681,18 +668,6 @@ export function transformDeclarations(context: TransformationContext): Transform
|
||||
if (!isPrimitiveLiteralValue(unwrappedInitializer)) {
|
||||
reportInferenceFallback(node);
|
||||
}
|
||||
|
||||
// Check if the initializer is a property access to an enum member (e.g., Foo.bar)
|
||||
// In this case, don't print with initializer - let it fall back to type annotation
|
||||
if (isPropertyAccessExpression(unwrappedInitializer)) {
|
||||
const constantValue = resolver.getConstantValue(unwrappedInitializer);
|
||||
// If it has a constant value (meaning it's an enum member reference),
|
||||
// don't use initializer and let it get a type instead
|
||||
if (constantValue !== undefined) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return resolver.createLiteralConstValue(getParseTreeNode(node, canHaveLiteralInitializer)!, symbolTracker);
|
||||
}
|
||||
return undefined;
|
||||
@@ -1076,12 +1051,12 @@ export function transformDeclarations(context: TransformationContext): Transform
|
||||
const oldWithinObjectLiteralType = suppressNewDiagnosticContexts;
|
||||
let shouldEnterSuppressNewDiagnosticsContextContext = (input.kind === SyntaxKind.TypeLiteral || input.kind === SyntaxKind.MappedType) && input.parent.kind !== SyntaxKind.TypeAliasDeclaration;
|
||||
|
||||
// Emit methods which are private as properties with no type information
|
||||
if (isMethodDeclaration(input) || isMethodSignature(input)) {
|
||||
if (hasEffectiveModifier(input, ModifierFlags.Private)) {
|
||||
if (input.symbol && input.symbol.declarations && input.symbol.declarations[0] !== input) return; // Elide all but the first overload
|
||||
return cleanup(factory.createPropertyDeclaration(ensureModifiers(input), input.name, /*questionOrExclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined));
|
||||
}
|
||||
// Emit methods which are private as properties with no type information
|
||||
if (isMethodDeclaration(input) || isMethodSignature(input)) {
|
||||
if (hasEffectiveModifier(input, ModifierFlags.Private)) {
|
||||
if (input.symbol && input.symbol.declarations && input.symbol.declarations[0] !== input) return; // Elide all but the first overload
|
||||
return cleanup(factory.createPropertyDeclaration(ensureModifiers(input), input.name, /*questionOrExclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined));
|
||||
}
|
||||
}
|
||||
|
||||
if (canProduceDiagnostic && !suppressNewDiagnosticContexts) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//// [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;
|
||||
}
|
||||
|
||||
// String enum
|
||||
enum StringEnum {
|
||||
Option1 = "option1",
|
||||
Option2 = "option2"
|
||||
}
|
||||
namespace StringEnum {
|
||||
export const selected = StringEnum.Option1;
|
||||
}
|
||||
|
||||
//// [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 = {}));
|
||||
// String enum
|
||||
var StringEnum;
|
||||
(function (StringEnum) {
|
||||
StringEnum["Option1"] = "option1";
|
||||
StringEnum["Option2"] = "option2";
|
||||
})(StringEnum || (StringEnum = {}));
|
||||
(function (StringEnum) {
|
||||
StringEnum.selected = StringEnum.Option1;
|
||||
})(StringEnum || (StringEnum = {}));
|
||||
@@ -0,0 +1,65 @@
|
||||
//// [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))
|
||||
}
|
||||
|
||||
// String enum
|
||||
enum StringEnum {
|
||||
>StringEnum : Symbol(StringEnum, Decl(enumNamespaceConstantsDeclaration.ts, 16, 1), Decl(enumNamespaceConstantsDeclaration.ts, 22, 1))
|
||||
|
||||
Option1 = "option1",
|
||||
>Option1 : Symbol(StringEnum.Option1, Decl(enumNamespaceConstantsDeclaration.ts, 19, 17))
|
||||
|
||||
Option2 = "option2"
|
||||
>Option2 : Symbol(StringEnum.Option2, Decl(enumNamespaceConstantsDeclaration.ts, 20, 24))
|
||||
}
|
||||
namespace StringEnum {
|
||||
>StringEnum : Symbol(StringEnum, Decl(enumNamespaceConstantsDeclaration.ts, 16, 1), Decl(enumNamespaceConstantsDeclaration.ts, 22, 1))
|
||||
|
||||
export const selected = StringEnum.Option1;
|
||||
>selected : Symbol(selected, Decl(enumNamespaceConstantsDeclaration.ts, 24, 16))
|
||||
>StringEnum.Option1 : Symbol(Option1, Decl(enumNamespaceConstantsDeclaration.ts, 19, 17))
|
||||
>StringEnum : Symbol(StringEnum, Decl(enumNamespaceConstantsDeclaration.ts, 16, 1), Decl(enumNamespaceConstantsDeclaration.ts, 22, 1))
|
||||
>Option1 : Symbol(Option1, Decl(enumNamespaceConstantsDeclaration.ts, 19, 17))
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
//// [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
|
||||
> : ^^^^^^^^^^^^^
|
||||
}
|
||||
|
||||
// String enum
|
||||
enum StringEnum {
|
||||
>StringEnum : StringEnum
|
||||
> : ^^^^^^^^^^
|
||||
|
||||
Option1 = "option1",
|
||||
>Option1 : StringEnum.Option1
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>"option1" : "option1"
|
||||
> : ^^^^^^^^^
|
||||
|
||||
Option2 = "option2"
|
||||
>Option2 : StringEnum.Option2
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>"option2" : "option2"
|
||||
> : ^^^^^^^^^
|
||||
}
|
||||
namespace StringEnum {
|
||||
>StringEnum : typeof StringEnum
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
|
||||
export const selected = StringEnum.Option1;
|
||||
>selected : any
|
||||
>StringEnum.Option1 : StringEnum.Option1
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
>StringEnum : typeof StringEnum
|
||||
> : ^^^^^^^^^^^^^^^^^
|
||||
>Option1 : StringEnum.Option1
|
||||
> : ^^^^^^^^^^^^^^^^^^
|
||||
}
|
||||
Reference in New Issue
Block a user