Skip to content

Fix unique symbol widening in expando property assignments#2903

Closed
Copilot wants to merge 2 commits intomainfrom
copilot/fix-unique-symbol-attribute
Closed

Fix unique symbol widening in expando property assignments#2903
Copilot wants to merge 2 commits intomainfrom
copilot/fix-unique-symbol-attribute

Conversation

Copy link
Contributor

Copilot AI commented Feb 25, 2026

Unique symbols assigned as expando properties (e.g., Objs.Sym = Sym) were incorrectly widened from unique symbol to symbol, breaking type narrowing via equality checks.

const Sym: unique symbol = Symbol("test");
const Objs = () => {};
Objs.Sym = Sym;

type Val = { attr: 1 } | typeof Objs.Sym;
const vals: Val[] = [Objs.Sym];
console.log(vals[0] != Objs.Sym && vals[0].attr); // TS2339 in tsgo, works in tsc

Cause

getAssignmentDeclarationInitializerType used checkExpressionForMutableLocation, which calls getWidenedLiteralLikeTypeForContextualTypegetWidenedUniqueESSymbolType, widening unique symbol to symbol. TypeScript's getInitializerTypeFromAssignmentDeclaration uses getWidenedLiteralType which does not widen unique symbols.

Fix

  • Replaced checkExpressionForMutableLocation in getAssignmentDeclarationInitializerType with inlined widening logic that applies getWidenedLiteralType (preserving contextual type handling for regular literals) but omits the getWidenedUniqueESSymbolType call.
  • Added compiler test uniqueSymbolPropertyNarrowing.ts covering both property-access and direct-identifier narrowing cases.
Original prompt

This section details on the original issue you should resolve

<issue_title>Unique symbol defined as attribute not narrowed</issue_title>
<issue_description>## Steps to reproduce

Behaviour difference between 6.0 and 7.0. The following snippet compiles without errors on earlier versions (which I believe is correct) but fails in the native preview with the below error.

const Sym: unique symbol = Symbol("test");
const Objs = () => {};
Objs.Sym = Sym;

type Val = { attr: 1} | typeof Objs.Sym;
const vals: Val[] = [Objs.Sym];
console.log(vals[0] != Objs.Sym && vals[0].attr);

Note that the following similar snippet works without error in both versions:

const Sym: unique symbol = Symbol("test");

type Val = { attr: 1 } | typeof Sym;
const vals: Val[] = [Sym];
console.log(vals[0] != Sym && vals[0].attr);

Behavior with [email protected]

$ npm exec -- tsc --noEmit test.ts && echo Success
Success

Behavior with tsgo

$ npm exec -- tsgo --noEmit test.ts && echo Success
test.ts:7:44 - error TS2339: Property 'attr' does not exist on type 'Val'.
  Property 'attr' does not exist on type 'symbol'.

7 console.log(vals[0] != Objs.Sym && vals[0].attr);
                                             ~~~~


Found 1 error in test.ts:7

</issue_description>

<agent_instructions>Write a test that shows the behavior first, commit that, then work on the issue.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

In getAssignmentDeclarationInitializerType, use getWidenedLiteralType
instead of getWidenedLiteralLikeTypeForContextualType (via
checkExpressionForMutableLocation) to avoid widening unique ES symbols.
This preserves contextual type handling for regular literals while not
incorrectly widening unique symbols to 'symbol', matching the behavior
of TypeScript's getInitializerTypeFromAssignmentDeclaration.

Co-authored-by: jakebailey <[email protected]>
Copilot AI changed the title [WIP] Fix unique symbol defined as attribute not narrowed Fix unique symbol widening in expando property assignments Feb 25, 2026
Copilot AI requested a review from jakebailey February 25, 2026 08:04
@jakebailey jakebailey closed this Feb 26, 2026
@jakebailey jakebailey deleted the copilot/fix-unique-symbol-attribute branch February 26, 2026 23:09
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.

Unique symbol defined as attribute not narrowed

2 participants