Skip to content

Error when property is specified more than once via a spread #36727

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Feb 11, 2020

Conversation

sandersn
Copy link
Member

@sandersn sandersn commented Feb 10, 2020

Add an error when we can be certain that a property declaration in an object literal will be overwritten by a later spread in the same object literal.
Updated from #27645

Notably, we can't be certain when:

  1. The spread element includes undefined in its type.
  2. The property from the spread element includes undefined in its type.
  3. strictNullChecks is off.

Also, duplicate property declarations in a property declaration without spreads is track

This PR currently has some cleanup and open questions:

  1. Is the removal of JSX errors correct? I thought I could unify them, but instead the errors don't happen at all; the previous version of this PR in Error: Property is overwritten by later spread #27645 it turns out the spread error message isn't correct for JSX anyway, so probably the correct change is not to try to unify the messages.
  2. I hate passing yet another flag into getSpreadType.
  3. Need to see whether ?. syntax applies in one place.

Edit: It's not just that strictNullChecks needs to be on -- the JSX errors are gone for some other reason.

Fixes #27355

@sandersn
Copy link
Member Author

@andrewbranch Mind taking a look at this, especially with an eye on the JSX errors?

@weswigham
Copy link
Member

Is the removal of JSX errors correct?

Definitely not - having a children explicit attribute and providing child elements is definitely an error.

@weswigham
Copy link
Member

weswigham commented Feb 11, 2020

I would just not remove the extra JSX error - it's there because it's essentially like you wrote {x: 12, x: 12} which we'd normally flag in the binder under strict mode checks (but this being jsx, we do not), and won't be flagged by the spread logic because the parenting structure isn't the same as a real spread.

@sandersn
Copy link
Member Author

I couldn't write code that produced the JSX error in my editor. It's not dependent on a particular version of React being installed is it? Maybe I was just using the wrong language service...

declare var abq: { a: number, b?: number };
var unused1 = { b: 1, ...ab } // error
var unused2 = { ...ab, ...ab } // ok, overwritten error doesn't apply to spreads
var unused3 = { b: 1, ...abq } // ok, abq might have b: undefined
Copy link
Member

Choose a reason for hiding this comment

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

It would be nice to add

var unused4 = { ...ab, b: 1 };
var unused5 = { ...abq, b: 1 };

just so the scope of the new error is clear to someone reading this test (me) (these should not be errors, right?)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, those are not errors. I added the cases.

// Error children are specified twice
return (<InnerButton {...this.props} children="hi">
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2710: 'children' are specified twice. The attribute named 'children' will be overwritten.
Copy link
Member

Choose a reason for hiding this comment

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

It’s unclear what this test was supposed to be testing. children are actually specified three times: first in the spread, then in the named attribute, then in the JSX children. IMO, it should never be an error to overwrite a spread property with a named declaration (in JSX props or object literals), but it would be quite reasonable to issue an error when a) a named declaration overwrites a named declaration, or b) a spread property overrides a named declaration (which is what this PR is about). And I’m counting JSX children (like the tag contents) as named, even though the name is implicit.

By way of example, here are the tests I think should probably exist at some point:

interface AnchorProps { href: string; children: string }
declare const props: AnchorProps;

const a1 = <a {...props} href="#" />; // ok: analgous to `p = { ...props, href: '#' }`
const a2 = <a {...props} children="Link" />; // ok: same as above
const a3 = <a {...props}>Link</a>; // ok: same as above

const a4 = <a href="#" {...props} />; // not ok (as of this PR): analgous to `p = { href: '#', ...props }`
const a5 = <a children="Link" {...props} />; // not ok: same as above

const a6 = <a children="Link">Link</a>; // I guess not ok, but kinda linty and unrelated to this PR

Copy link
Member

Choose a reason for hiding this comment

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

const a6 = <a children="Link">Link</a>; // I guess not ok, but kinda linty and unrelated to this PR

is the case the old error was mostly concerned with catching~

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I just reverted the JSX changes since it's just going to hold up this PR to try to unify what appears to be an actually-quite-different-and-complex check.

@@ -2683,7 +2683,7 @@
"category": "Error",
"code": 2733
},
"It is highly likely that you are missing a semicolon.": {
"Are you missing a semicolon?": {
Copy link
Member

Choose a reason for hiding this comment

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

“$20 says you’re missing a semicolon”

@sandersn sandersn merged commit a772c26 into master Feb 11, 2020
@sandersn sandersn deleted the object-spread-property-specified-twice branch February 11, 2020 18:23
@sandersn
Copy link
Member Author

Because the error reporting distributes across unions, this gives an extraneous error for types like { a } | {}, which should really have a optional. I don't want to do a second pass over the properties for this error, but I'm not yet sure how to.

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.

Missing excess property error with spread
3 participants