Skip to content

Bug in array destructuring (compile error if destructured, but no error if direct attribute access) #37085

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

Closed
ecbrodie opened this issue Feb 27, 2020 · 2 comments

Comments

@ecbrodie
Copy link

TypeScript Version: 3.8.2 (reproduced on next as of publishing time, which was 3.9.0-dev.20200227)

Search Terms: "array destructuring", "array object destructuring"

Code

I am trying to utilize TypeScript bindings for the following function provided by documentation for graphql-ruby, for a TypeScript React project utilizing Apollo as a GraphQL client and Rails as the server:

import { ApolloLink } from "apollo-link"

...

const hasSubscriptionOperation = ({ query: { definitions } }) => {
  return definitions.some(
    ({ kind, operation }) => kind === 'OperationDefinition' && operation === 'subscription'
  )
}

const link = ApolloLink.split(
  hasSubscriptionOperation,
  new ActionCableLink({cable}),
  httpLink
);

According to the type bindings for ApolloLink.split, I should be able to add the type binding of Operation to the single parameter of hasSubscriptionOperation, like so:

const hasSubscriptionOperation = ({ query: { definitions } }: Operation) => {
  return definitions.some(
    ({ kind, operation }) => kind === 'OperationDefinition' && operation === 'subscription'
  )
}

Expected behavior:

There should be no tsc errors. The object destructuring on the definitions.some() parameter is valid because kind and operation are both valid attributes.

Actual behavior:

Nope! I am getting a compile error on the operation destructured parameter. BUT, what's weird is that if I rely on direct attribute access instead of destructuring, then I get no compile time issues, like so:

const hasSubscriptionOperation = ({ query: { definitions } }: Operation) => {
  return definitions.some(
    (definition) => definition.kind === 'OperationDefinition' && definition.operation === 'subscription'
  )
}

Bug in destructuring???

Playground Link:

I could not get this to work in TypeScript Playground. So, hopefully CodeSandbox will suffice. See index.ts. https://codesandbox.io/s/friendly-thunder-nsicx

Related Issues:

I noticed this open bug, but it appeared to be describing a separate issue on first glance: #32465

Also this bug, but it appears to be closed as fixed: #33282

@IllusionMH
Copy link
Contributor

IllusionMH commented Feb 28, 2020

Because DefinitionNode is union of different types and it looks like only OperationDefinitionNode has operation key. Therefore it's not in list of common properties and cannot be safely accesses for all types from union.

In second example you first narrow union to only OperationDefinitionNode type and then you can access this key without any problems.

Change definition.kind === 'OperationDefinition' to VariableDefinition and you'll see same error.

Just remove definition.kind === 'OperationDefinition' && or do manual destructuring to see similar error:
image

And since you relying on narrowing in this case you can't use destructuring in arguments because of #12184 (closer example #28599)

@ecbrodie
Copy link
Author

ecbrodie commented Mar 3, 2020

@IllusionMH thank you for the explanation. I guess I did not know enough about union narrowing in TypeScript before I filed this issue. Now, I fully understand what is going on; by checking that definition.kind === 'OperationDefinition', I've narrowed down the union type to be OperationDefinitionNode, which is the only union type that contains an operation key.

I shall close this out now.

@ecbrodie ecbrodie closed this as completed Mar 3, 2020
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

No branches or pull requests

2 participants