Skip to content

Fix destructuring with fallback #31711

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 7 commits into from
Jun 2, 2019
Merged

Conversation

ahejlsberg
Copy link
Member

@ahejlsberg ahejlsberg commented May 31, 2019

With this PR we properly permit destructurings to specify fallbacks:

function f1(options?: { color: string, width?: number }) {
    let { color, width } = options || {};  // Was error, now ok
}

function f2(options?: [string, number?]) {
    let [str, num] = options || [];  // Was error, now ok
}

Previously we would complain that "Initializer provides no value for this binding element and the binding element has no default value".

Fixes #26235.

@ahejlsberg
Copy link
Member Author

@typescript-bot test this
@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 1, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at 0895fd6. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 1, 2019

Heya @ahejlsberg, I've started to run the extended test suite on this PR at 0895fd6. You can monitor the build here. It should now contribute to this PR's status checks.

@ajafff
Copy link
Contributor

ajafff commented Jun 1, 2019

Will this also work with non-optional properties/elements?

function f1(options?: { color: string, width: number }) {
    let { color, width } = options || {};  // does this result in 'color: string | undefined' and 'width: number | undefined'?
}

function f2(options?: [string, number]) {
    let [str, num] = options || []; 
}

@ahejlsberg
Copy link
Member Author

ahejlsberg commented Jun 1, 2019

Will this also work with non-optional properties/elements?

We need a few more tweaks to make that work. We currently consider (options || {}).color to be an invalid property access, but it ought to be allowed since we know we'll read undefined from the object literal.

@ahejlsberg
Copy link
Member Author

@typescript-bot test this
@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 1, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at 48d343b. You can monitor the build here. It should now contribute to this PR's status checks.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jun 1, 2019

Heya @ahejlsberg, I've started to run the extended test suite on this PR at 48d343b. You can monitor the build here. It should now contribute to this PR's status checks.

@ahejlsberg ahejlsberg merged commit d6c323a into master Jun 2, 2019
@ahejlsberg ahejlsberg deleted the fixDestructuringWithFallback branch June 2, 2019 00:30
@mihailik
Copy link
Contributor

mihailik commented Jun 3, 2019

@ajafff
Will this also work with non-optional properties/elements?

@ahejlsberg
We need a few more tweaks to make that work. We currently consider (options || {}).color to be an invalid property access, but it ought to be allowed since we know we'll read undefined from the object literal.

I don't think that's right?

The protection here is not just for runtime error, but also for typos. As @RyanCavanaugh implied in his comment, the intention is to catch errors like this:

function getColorOption(options: { color: string }) {
  return (options || {}).colour;
}

@mihailik
Copy link
Contributor

mihailik commented Jun 3, 2019

To clarify: this change is brilliant and very helpful. Thanks a lot!!

Allowing the same for non-optional fields is what sounds wrong to me.

@ahejlsberg
Copy link
Member Author

ahejlsberg commented Jun 3, 2019

...the intention is to catch errors like this

Your example with the misspelled property is still an error (the || {} doesn't affect the type as the left argument is known to always be truthy). But consider this:

function getColorOption(options?: { color: string }) {
  return (options || {}).color;
}

Here we now add undefined to the resulting type because it is known we'll read undefined from a property that doesn't exist in an object literal. And you'll still get an error for a misspelled property.

@ajafff
Copy link
Contributor

ajafff commented Jun 3, 2019

@ahejlsberg it's actually possible for typos to sneak into the fallback object literal:

function getColorOption(options?: { color: string }) {
  return (options || {colour: 'red'}).color;
}

Would it make sense to use the LHS type as contextual type for the RHS and do excess property checking? Or would that break all other uses of fallback objects?

@sandersn sandersn added the Breaking Change Would introduce errors in existing code label Jun 5, 2019
@sandersn sandersn added this to the TypeScript 3.6.0 milestone Jun 5, 2019
@sandersn
Copy link
Member

sandersn commented Jun 5, 2019

This is a breaking change in prettier. See #31762 for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking Change Would introduce errors in existing code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Error when destructuring with literal initializers as fallback
6 participants