From bb5e724b8fac6066147ff1795d8f0b2087ead349 Mon Sep 17 00:00:00 2001 From: Abhi <171412961+iapoorv01@users.noreply.github.com> Date: Fri, 3 Jul 2026 14:09:51 +0530 Subject: [PATCH] Fix ts2845 not firing for exported and imported enum members When an enum is exported or imported, the control flow analysis incorrectly suppressed the ts2845 error (This condition will always return 'true') for known truthy conditions like testing AdapterOutputType.PAGES. This occurred because checkTestingKnownTruthyType failed to resolve the local reference's SymbolFlagsExportValue or SymbolFlagsAlias back to the underlying SymbolFlagsEnum. Since Flags & ast.SymbolFlagsEnum resulted in 0, the check was skipped entirely. This commit introduces resolveAlias and getExportSymbolOfValueSymbolIfExported checks to properly unwrap the symbol and correctly identify the Enum, thus restoring the expected truthiness evaluation logic for open-ended enums. Fixes microsoft/TypeScript#63565 --- internal/checker/checker.go | 15 ++++++++--- .../compiler/exportEnumConditionAlwaysTrue.ts | 25 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 testdata/tests/cases/compiler/exportEnumConditionAlwaysTrue.ts diff --git a/internal/checker/checker.go b/internal/checker/checker.go index b639d488e4..8fc53dc2b7 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -3829,10 +3829,17 @@ func (c *Checker) checkTestingKnownTruthyType(condExpr *ast.Node, condType *Type if location != condExpr { t = c.checkExpression(location) } - if t.flags&TypeFlagsEnumLiteral != 0 && ast.IsPropertyAccessExpression(location) && core.OrElse(c.getResolvedSymbolOrNil(location.Expression()), c.unknownSymbol).Flags&ast.SymbolFlagsEnum != 0 { - // EnumLiteral type at condition with known value is always truthy or always falsy, likely an error - c.error(location, diagnostics.This_condition_will_always_return_0, core.IfElse(evaluator.IsTruthy(t.AsLiteralType().value), "true", "false")) - return + if t.flags&TypeFlagsEnumLiteral != 0 && ast.IsPropertyAccessExpression(location) { + exprSymbol := core.OrElse(c.getResolvedSymbolOrNil(location.Expression()), c.unknownSymbol) + if exprSymbol.Flags&ast.SymbolFlagsAlias != 0 { + exprSymbol = c.resolveAlias(exprSymbol) + } + exprSymbol = c.getExportSymbolOfValueSymbolIfExported(exprSymbol) + if exprSymbol.Flags&ast.SymbolFlagsEnum != 0 { + // EnumLiteral type at condition with known value is always truthy or always falsy, likely an error + c.error(location, diagnostics.This_condition_will_always_return_0, core.IfElse(evaluator.IsTruthy(t.AsLiteralType().value), "true", "false")) + return + } } isPropertyExpressionCast := ast.IsPropertyAccessExpression(location) && isTypeAssertion(location.Expression()) if !c.hasTypeFacts(t, TypeFactsTruthy) || isPropertyExpressionCast { diff --git a/testdata/tests/cases/compiler/exportEnumConditionAlwaysTrue.ts b/testdata/tests/cases/compiler/exportEnumConditionAlwaysTrue.ts new file mode 100644 index 0000000000..23620d7031 --- /dev/null +++ b/testdata/tests/cases/compiler/exportEnumConditionAlwaysTrue.ts @@ -0,0 +1,25 @@ +module A { + export enum ExportedEnum { + APP_PAGE = 1, + PAGES = 2, + } +} + +import ImportedEnum = A.ExportedEnum; + +// Test 1: Exported enum directly +declare const type1: A.ExportedEnum; +const kind1 = type1 === A.ExportedEnum.APP_PAGE || A.ExportedEnum.PAGES ? 'left' : 'right'; + +// Test 2: Imported enum alias +declare const type2: ImportedEnum; +const kind2 = type2 === ImportedEnum.APP_PAGE || ImportedEnum.PAGES ? 'left' : 'right'; + +// Test 3: Normal enum (baseline verification) +enum NormalEnum { + A = 1, + B = 2, +} + +declare const type3: NormalEnum; +const kind3 = type3 === NormalEnum.A || NormalEnum.B ? 'left' : 'right';