Skip to content

Conversation

@tt-a1i
Copy link
Contributor

@tt-a1i tt-a1i commented Dec 12, 2025

Summary

This PR fixes #25083 where enum keys accessed with bracket notation (e.g., Type['3x14']) were not recognized as valid computed property names in type literals, even when they resolved to literal types.

The problem

enum Type {
  Foo = 'foo',
  '3x14' = '3x14'  // Non-identifier enum key
}

type TypeMap = {
  [Type.Foo]: any;        // ✅ Works
  [Type['3x14']]: any;    // ❌ Error: TS1170 - but should work!
}

The error occurred because isLateBindableAST only recognized EntityNameExpression (Identifier or PropertyAccessExpression) but not ElementAccessExpression with literal keys.

The fix

Introduced isLateBindableAccessExpression, a helper function that recursively validates access expressions:

  • Identifiers
  • PropertyAccessExpression where the name is an Identifier (not PrivateIdentifier) and the base is valid
  • ElementAccessExpression where the argument is a string/numeric literal (after skipping parentheses) and the base is valid
  • Parenthesized expressions are skipped via skipParentheses

This supports:

  • Pure property access: obj.a.b.c
  • Pure element access: obj['a']['b']['c']
  • Mixed chains: obj.a['b'].c['d']
  • Parenthesized expressions: (obj.a)['b']
  • Parenthesized keys: obj[('a')]

Also updated checkGrammarForInvalidDynamicName to use the new helper (it handles skipParentheses internally now).

Testing

Added test case enumKeysAsComputedPropertiesWithBracketNotation.ts covering:

  • Enum keys with bracket notation (Type['3x14'])
  • Bracket notation with identifier keys (Type['Foo'])
  • Nested element access (obj['a']['b'])
  • Mixed chains (obj['a'].b, obj.a['b'])
  • Complex mixed chains (deep.a['b'].c['d'])
  • Parenthesized expressions ((obj.a).b, (obj['a']).b)
  • Parenthesized keys (obj[('a')], deep[('a')][('b')].c['d'])

Baseline changes

enumKeysAsComputedPropertiesWithBracketNotation.*

  • New test file baselines for the fix

isolatedDeclarationLazySymbols.errors.txt

  • Removed false positive error for Direction['Up'] in [Direction['Up']]: number
  • This was previously incorrectly flagged as TS1170 because Direction['Up'] wasn't recognized as a valid late-bindable name
  • Now correctly allows this pattern since it resolves to a literal type "UP"

isolatedDeclarationLazySymbols.types

  • The type for [Direction['Up']] now correctly resolves to "UP" instead of showing error
  • This reflects the fix allowing element access on enums to be used as computed property names

All 99,161 tests pass.

This fixes microsoft#25083 where enum keys accessed with bracket notation
(e.g., `Type['3x14']`) were not recognized as valid computed property
names in type literals, even when they resolved to literal types.

The fix extends `isLateBindableAST` to recognize `ElementAccessExpression`
with string or numeric literal keys as valid late-bindable expressions,
similar to how `PropertyAccessExpression` is already handled.

This also updates `checkGrammarForInvalidDynamicName` to allow such
expressions as computed property names.
@github-project-automation github-project-automation bot moved this to Not started in PR Backlog Dec 12, 2025
@typescript-bot typescript-bot added the For Backlog Bug PRs that fix a backlog bug label Dec 12, 2025
@tt-a1i
Copy link
Contributor Author

tt-a1i commented Dec 12, 2025

@microsoft-github-policy-service agree

- Rename isEntityNameOrElementAccessExpression to isLateBindableAccessExpression
- Support mixed chains like obj.a['b'].c['d']
- Add skipParentheses handling for expressions like (obj.a)['b']
- Ensure PropertyAccessExpression name is Identifier (not PrivateIdentifier)
- Add comprehensive test cases for mixed chains and parenthesized expressions
Support obj[('a')] by applying skipParentheses to argumentExpression
before checking isStringOrNumericLiteralLike.

Added test cases for parenthesized keys in element access.
- Fix declaration emit elide condition to recognize ElementAccessExpression
  as a valid late-bindable expression (declarations.ts:1026)
- Update isolatedDeclarations check to accept late-bindable access expressions
  (declarations.ts:1019)
- Add LateBindableAccessExpression type alias for clearer semantics
- Extract isLateBindableAccessExpression to utilities.ts and remove duplicate
  implementation from checker.ts
- Update getFirstIdentifier to support ElementAccessExpression chains
- Update isEntityNameVisible and related APIs to accept ElementAccessExpression
- Add test case with @declaration: true to verify computed properties are
  preserved in generated .d.ts files
- Add reference baselines for enumKeysExportScenario test
- Fix getFirstIdentifier to skipParentheses when traversing access chains
  to handle cases like (obj.a)['b']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Backlog Bug PRs that fix a backlog bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

Enum keys not accepted as computed properties if their name is not a valid identifier

2 participants