Skip to content

Preserve enum computed property names in declarations - #4852

Open
Jake Bailey (jakebailey) wants to merge 3 commits into
mainfrom
jabaile/fix-4850
Open

Preserve enum computed property names in declarations#4852
Jake Bailey (jakebailey) wants to merge 3 commits into
mainfrom
jabaile/fix-4850

Conversation

@jakebailey

@jakebailey Jake Bailey (jakebailey) commented Aug 8, 2026

Copy link
Copy Markdown
Member

Fixes #4850

This is a bug even in Strada; inlining the value means it's no longer of the enum type and things break.

See the second commit and how it drops the dts error.

@jakebailey
Jake Bailey (jakebailey) marked this pull request as ready for review August 10, 2026 18:57
Copilot AI balanced review requested due to automatic review settings August 10, 2026 18:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Preserves enum member identity when serializing computed property names into declaration types.

Changes:

  • Emits accessible enum members as computed property names.
  • Adds string and numeric enum regression coverage.
  • Updates local and accepted submodule baselines.

Reviewed changes

Copilot reviewed 42 out of 42 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
internal/checker/nodebuilderimpl.go Adds enum-aware property-name serialization.
testdata/tests/cases/compiler/enumComputedPropertyDeclarationEmit.ts Adds regression cases.
testdata/submoduleAccepted.txt Registers intentional baseline divergences.
testdata/baselines/reference/compiler/enumComputedPropertyDeclarationEmit.js Records declaration emit.
testdata/baselines/reference/compiler/enumComputedPropertyDeclarationEmit.types Records inferred types.
testdata/baselines/reference/compiler/enumComputedPropertyDeclarationEmit.symbols Records symbol bindings.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitComputedNameConstEnumAlias.js.diff Accepts declaration delta.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitComputedNameConstEnumAlias.types.diff Accepts type delta.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitComputedPropertyNameEnum1.types.diff Accepts type delta.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitStringEnumUsedInNonlocalSpread.types.diff Accepts spread type delta.
testdata/baselines/reference/submoduleAccepted/compiler/duplicateObjectLiteralProperty_computedName2.types.diff Accepts computed-name delta.
testdata/baselines/reference/submoduleAccepted/compiler/duplicateObjectLiteralProperty_computedName3.types.diff Accepts imported-name delta.
testdata/baselines/reference/submoduleAccepted/compiler/isolatedDeclarationErrorsObjects.types.diff Accepts isolated-declaration delta.
testdata/baselines/reference/submoduleAccepted/compiler/objectLiteralEnumPropertyNames.types.diff Accepts enum property types.
testdata/baselines/reference/submoduleAccepted/compiler/reducibleIndexedAccessTypes.types.diff Accepts indexed-access delta.
testdata/baselines/reference/submoduleAccepted/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty11.types.diff Accepts numeric-enum delta.
testdata/baselines/reference/submoduleAccepted/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty12.types.diff Accepts string-enum delta.
testdata/baselines/reference/submoduleAccepted/conformance/computedPropertyNames47_ES5(target=es2015).types.diff Accepts ES5 conformance delta.
testdata/baselines/reference/submoduleAccepted/conformance/computedPropertyNames47_ES6.types.diff Accepts ES6 conformance delta.
testdata/baselines/reference/submoduleAccepted/conformance/computedPropertyNames48_ES5(target=es2015).types.diff Accepts ES5 conformance delta.
testdata/baselines/reference/submoduleAccepted/conformance/computedPropertyNames48_ES6.types.diff Accepts ES6 conformance delta.
testdata/baselines/reference/submoduleAccepted/conformance/computedPropertyNames7_ES5(target=es2015).types.diff Accepts ES5 enum-name delta.
testdata/baselines/reference/submoduleAccepted/conformance/computedPropertyNames7_ES6.types.diff Accepts ES6 enum-name delta.
testdata/baselines/reference/submoduleAccepted/conformance/destructuringObjectBindingPatternAndAssignment7(target=esnext).types.diff Accepts destructuring delta.
testdata/baselines/reference/submodule/compiler/declarationEmitComputedNameConstEnumAlias.js Updates declaration baseline.
testdata/baselines/reference/submodule/compiler/declarationEmitComputedNameConstEnumAlias.types Updates type baseline.
testdata/baselines/reference/submodule/compiler/declarationEmitComputedPropertyNameEnum1.types Updates type baseline.
testdata/baselines/reference/submodule/compiler/declarationEmitStringEnumUsedInNonlocalSpread.types Updates spread baseline.
testdata/baselines/reference/submodule/compiler/duplicateObjectLiteralProperty_computedName2.types Updates computed-name baseline.
testdata/baselines/reference/submodule/compiler/duplicateObjectLiteralProperty_computedName3.types Updates imported-name baseline.
testdata/baselines/reference/submodule/compiler/isolatedDeclarationErrorsObjects.types Updates isolated-declaration baseline.
testdata/baselines/reference/submodule/compiler/objectLiteralEnumPropertyNames.types Updates enum property baseline.
testdata/baselines/reference/submodule/compiler/reducibleIndexedAccessTypes.types Updates indexed-access baseline.
testdata/baselines/reference/submodule/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty11.types Updates numeric-enum baseline.
testdata/baselines/reference/submodule/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty12.types Updates string-enum baseline.
testdata/baselines/reference/submodule/conformance/computedPropertyNames47_ES5(target=es2015).types Updates ES5 conformance baseline.
testdata/baselines/reference/submodule/conformance/computedPropertyNames47_ES6.types Updates ES6 conformance baseline.
testdata/baselines/reference/submodule/conformance/computedPropertyNames48_ES5(target=es2015).types Updates ES5 conformance baseline.
testdata/baselines/reference/submodule/conformance/computedPropertyNames48_ES6.types Updates ES6 conformance baseline.
testdata/baselines/reference/submodule/conformance/computedPropertyNames7_ES5(target=es2015).types Updates ES5 enum-name baseline.
testdata/baselines/reference/submodule/conformance/computedPropertyNames7_ES6.types Updates ES6 enum-name baseline.
testdata/baselines/reference/submodule/conformance/destructuringObjectBindingPatternAndAssignment7(target=esnext).types Updates destructuring baseline.
Suppressed comments (1)

internal/checker/nodebuilderimpl.go:2473

  • This predicate is both unsafe for a nil context and too narrow for qualified enums. With a nil enclosing declaration (used by inlay hints), symbolToExpression receives only the member symbol and prints [A] instead of [E.A]; conversely, an enum nameable only as N.E has no direct accessible chain and is unnecessarily inlined. Require a real context (or deliberately fall back to the literal) and use the container-aware value-symbol accessibility path so qualified enum chains are accepted.
		if enumEnclosingDeclaration == nil ||
			len(b.ch.getAccessibleSymbolChain(enumSymbol, enumEnclosingDeclaration, ast.SymbolFlagsValue, false)) > 0 {

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +2463 to +2466
enumEnclosingDeclaration := enclosingDeclaration
if b.ctx.enclosingFile != nil {
enumEnclosingDeclaration = b.ctx.enclosingFile.AsNode()
}

@weswigham Wesley Wigham (weswigham) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've known about this for awhile - I was hoping we'd move this way after the changes for ID to preserve computed names more often.

The only thing is that while this makes the immediate cases better (obviously) by serializing as a computed name when the name type of a property is enum-y, we still compare enum and same-string-non-enum property names identically, so you can still lose key enum-yness through aliasing (eg, NonEnumKeys | EnumKeys may simplify to NonEnumKeys and now your remapping over it that prints an anonymous type loses it's key enum-y-ness) - a notable hole in the typesystem that this fix kinda glosses over without fixing, but maybe that's OK. We've had this issue ever since we made keyof track enums instead of underlying literals, but never really settled on a way we wanted to close the hole.

Comment thread internal/checker/nodebuilderimpl.go Outdated
enumSymbol = nameType.symbol
}
if enumEnclosingDeclaration == nil ||
len(b.ch.getAccessibleSymbolChain(enumSymbol, enumEnclosingDeclaration, ast.SymbolFlagsValue, false)) > 0 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, rather than checking chain length (what?) this should just be IsSymbolAccessible, no?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR was of course a first copilot attempt after talking to Chris on discord, I hadn't actually reviewed it quite yet; will go fix that

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

embarassing as copilot memory is now disabled by default and it decides to randomly comment :<

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Difference in behavior of enum used as field key in emit vs non-emit type check

3 participants