Skip to content

fix: allow bracket-notation enum access as computed property name in type positions#63434

Open
Scolliq wants to merge 1 commit intomicrosoft:mainfrom
Scolliq:fix/enum-bracket-computed-key
Open

fix: allow bracket-notation enum access as computed property name in type positions#63434
Scolliq wants to merge 1 commit intomicrosoft:mainfrom
Scolliq:fix/enum-bracket-computed-key

Conversation

@Scolliq
Copy link
Copy Markdown

@Scolliq Scolliq commented Apr 25, 2026

Problem

Enum members with non-identifier names (e.g. 'hello world', '3x14') could not be used as computed property keys in type literals or interfaces using bracket notation, even though the expression evaluates to a well-known string literal type.

enum E { "hello world" = "hw" }

// Works fine:
type A = { [E.normal]: string };

// Error TS1170 — but shouldn't be:
type B = { [E["hello world"]]: string };
interface C { [E["hello world"]]: string; }

The error message says "must refer to an expression whose type is a literal type" — but E["hello world"] IS a string literal type. The check was incorrectly using expression shape (entity name expression) as a proxy for the type.

Fixes #25083.

Root Cause

isLateBindableAST only recognised EntityNameExpression forms (identifiers and property-access chains like A.B.C) as potentially late-bindable. Element-access expressions like E["hello world"] were unconditionally rejected, making isNonBindableDynamicName return true and triggering the grammar error.

Fix

Extended isLateBindableAST to also return true when the expression is an ElementAccessExpression whose object is an entity name and whose argument is a string or numeric literal:

// Also allow element access on an entity name with a literal key, e.g. Enum['non-identifier-key'].
return isElementAccessExpression(expr)
    && isEntityNameExpression(expr.expression)
    && isStringOrNumericLiteralLike(skipParentheses(expr.argumentExpression));

isLateBindableName already checks isTypeUsableAsPropertyName on the resolved type, so this only opens the door for expressions that actually evaluate to a usable property name type (string/number literal or unique symbol).

Tests

Added tests/cases/compiler/enumBracketComputedPropertyName.ts covering:

  • Type literal with bracket-notation enum key (E["hello world"], E["3x14"])
  • Interface with bracket-notation enum key
  • Round-trip access through the computed key

Updated isolatedDeclarationLazySymbols baselines to reflect improved behaviour: TS1166 no longer fires for [o["prop.inner"]] in a class (correct — the type is a literal), and foo[o["prop.inner"]] now correctly resolves to string instead of any.

…type positions

Extends isLateBindableAST to recognise element access expressions of the
form Enum['non-identifier-key'] (entity name indexed by a string/numeric
literal) as late-bindable, in addition to the previously-supported
Enum.Foo property-access style.

Previously, enum members whose names are not valid identifiers (e.g.
E['hello world'], E['3x14']) could not be used as computed property keys
in type literals or interfaces, even though the expression evaluates to a
well-known string literal type and the error message explicitly says that
literal types are allowed.

Fixes microsoft#25083
@github-project-automation github-project-automation Bot moved this to Not started in PR Backlog Apr 25, 2026
@typescript-bot typescript-bot added the For Backlog Bug PRs that fix a backlog bug label Apr 25, 2026
@Scolliq
Copy link
Copy Markdown
Author

Scolliq commented Apr 25, 2026

@microsoft-github-policy-service agree

@jakebailey
Copy link
Copy Markdown
Member

Can you please tell me what tool you used to send this PR, and how you chose this issue to fix?

@Scolliq
Copy link
Copy Markdown
Author

Scolliq commented Apr 25, 2026

Can you please tell me what tool you used to send this PR, and how you chose this issue to fix?

I used Claude Code to help scan large open-source codebases for unfixed issues. It surfaced this one, and I went through the root cause with the help of the opus 4.7 model tracing isLateBindableAST and understanding why element access expressions on entity names weren't being treated as late-bindable the same way property-access ones are. I study computer science, this isnt just a blind purely vibecoded small commit. I have also read the typescript repos rules on AI tools in the CONTRIBUTING.md

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

3 participants