Skip to content

Wrong types inferred and false-positive ts(2783) when spreading object literals with "inline" __proto__ #45580

Closed

Description

@worstpractice

Bug Report

Hello everyone, first time issue reporter here ヾ(•ω•`)o Thank you so much in advance for all the great work ♥

Related: #38385, #42359

The notes that follow are based on this playground.

NOTE: None of the flags I have set in that link matter or influence the result, they are simply some flags I like.

Please note that all the properties involved in this example are (AFAIK) statically known (to the extent reasonably possible, including as const for objects). Even so, the wrong types are inferred.

The bug

One compiler error (2783) and one explainer/hint message appear when hovering over the single squiggly line.

  1. 'proto' is specified more than once, so this usage will be overwritten.(2783)

  2. This spread always overwrites this property.

Both are in fact wrong (in this special case, specifically involving __proto__ in object literals).

To the best of my knowledge, spreading could never overwrite a __proto__ declared "inline" (in the same object literal), irrespective (!) of ordering.

Put another way: no matter where (in the object literal) __proto__ appears — if it's there at all, it "wins" automatically.

Furthermore, hovering over protoFollowedBySpread reveals its inferred type to be:

{ readonly __proto__: null; }

...which is incorrect. The actual __proto__ is Array.prototype, which is why console.log('map' in protoFollowedBySpread) logs true at runtime.

Considering the broken type inference, I would wager to guess that the type checker is (as of yet) uneducated on the particular semantics at play in this somewhat rare (though well-defined) corner case of the language.

🔎 Search Terms

  • proto
  • spread
  • object literal
  • ts(2783)
  • specified more than once
  • will be overwritten

🕗 Version & Regression Information

This was the behavior I observed in every version I tried.

⏯ Playground Link

Playground link with relevant code

💻 Code

export const foo = {
  __proto__: null,
} as const;

export const protoFollowedBySpread = {
  __proto__: Array.prototype, // This error is itself erroneous (in this one special case, specifically involving `__proto__` in object literals).
  ...foo,
} as const;

export const spreadFollowedByProto = {
  ...foo,
  __proto__: Array.prototype, // No error is reported when the "inline" `__proto__` comes AFTER `...foo`. No surprises here. ;
} as const; 

console.log('map' in protoFollowedBySpread); // logs `true`(the inferred type is wrong)

🙁 Actual behavior

Please see the playground. In short:

  • Invalid type inference
  • False positive ts(2783)
  • Hint that (while a wonderful and friendly feature) happens to mislead in this particular case

🙂 Expected behavior

Simply put, a correct understanding of the language semantics in this case. Notable mentions here would be (two sides of the same coin):

  • No errors reported where nothing is wrong
  • Correctly inferring the type based on the (AFAIK) statically known properties involved

Activity

  1. added
    BugA bug in TypeScript
    and removed
    BugA bug in TypeScript
    on Aug 26, 2021
  2. andrewbranch commented on Aug 26, 2021

    @andrewbranch
    Member

    You are right, but this doesn’t seem like it needs to be a separate issue from #38385. We wouldn’t have any business understanding that __proto__ is special in a spread without understanding the other ways in which __proto__ is special. Maybe you’d like to comment on the related issue or PR instead to ensure this test case is covered?

  3. typescript-bot commented on Aug 28, 2021

    @typescript-bot
    Contributor

    This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  4. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions