graphql-code-generator icon indicating copy to clipboard operation
graphql-code-generator copied to clipboard

[typescript-vue-apollo-smart-ops] The TypeScript types for subscriptions are completely broken

Open fabis94 opened this issue 2 years ago • 3 comments

Describe the bug

I'm wondering how no one's noticed this before, but the subscription functions generated using createSmartSubscriptionOptionsFunction return incomplete or even invalid types.

The main issues are:

  1. There's no generic argument for specifying the value of this inside the options functions like variables(). The functions generated for standard queries & mutations do have this argument, however. Instead, by default the this value seems to just be the options object, which definitely is a bug.
apollo: {
  $subscribe: {
    userCreated: useUserCreatedSubscription({
      variables() {
        return {
          id: this.id, // TS will throw an error that `this` does not have an `id` field, even if it's available in the Vue component
        }
      }
    })
  }
}

The examples in the docs also only show variables having static/hardcoded values, even tho no one's ever going to have static/hardcoded variables for these operations. Almost always you're going to want to rely on the properties of the Vue component to resolve the variables.

  1. The subscription options type doesn't specify that the result and skip functions are available, so if you use them, TS will throw an error. This issue I was at least able to solve myself through type augmentation.

Lastly, I wanted to comment on the fact that the need to specify the type of this inside these option objects isn't very good DX in the first place, because you end up duplicating these types first in the actual Vue component and then inside this generic argument. But here I will assume that there's a technical reason why these functions can't correctly resolve the this values automatically.

data() {
  return {id: null}
},
apollo: {
  user: useMainUserDataQuery<Vue & {id: null | string}>({
    variables() {
      return { id: this.id }
    }
  })
}

Your Example Website or App

none

Steps to Reproduce the Bug or Issue

No reproduction is really necessary, you can just look at the TS type definitions to see what I mean. I also tried to provide short code examples above.

Expected behavior

  1. Subscription option type should contain a definition for the skip() and result() functions
  2. Subscription type should either infer the Vue component's this value correctly or at the very least allow specifying it through a generic argument

Screenshots or Videos

No response

Platform

  • OS: Ubuntu 20
  • NodeJS: 16.14.0
  • graphql version: 15.8.0
  • @graphql-codegen/typescript-vue-apollo-smart-ops version: 2.3.1

Codegen Config File

overwrite: true
schema: 'http://localhost:3000/graphql'
documents:
  - 'src/graphql/**/*.gql'
  - 'src/**/*.{ts,tsx,js,jsx,vue}'
generates:
  src/graphql/generated/graphql.ts:
    plugins:
      - 'typescript'
      - 'typescript-operations'
      - 'typescript-document-nodes'
      - 'typescript-vue-apollo-smart-ops'
    config:
      vueApolloErrorHandlerFunction: handleApolloError
      vueApolloErrorHandlerFunctionImportFrom: '@/config/vueApolloSmartOpsConfig'
      scalars:
        JSONObject: Record<string, unknown>

Additional context

No response

fabis94 avatar Jul 14 '22 07:07 fabis94

Are you using Vue 3?

I had to write a patch script to get it working with Vue 3.

Something along those lines:

const patchVue3 = () => {
  let file = fs.readFileSync(options.typesPath, "utf-8").toString();
  file = file.split("@vue/composition-api").join("vue");
  fs.writeFileSync(options.typesPath, file);
  console.log(clc.green(`[codegen] Vue3 patch applied to ${options.typesPath}`));
}

cwdx avatar Jul 21 '22 03:07 cwdx

@cwdx Nope, this is just on Vue 2. I ended up discarding this plugin, it's too much trouble than it's worth. Besides the issues I mentioned, the core vue-apollo-smart-ops lib relies on an old version of Apollo Client (v2), which is another deal breaker.

fabis94 avatar Jul 21 '22 07:07 fabis94

If you are using Vue 3 (and especially if you are using vue apollo 4 composables), I highly recommend checking out typed-document-node documentation.

It is a more generic way to get typed graphql query support and is supported by the most popular graphql libraries (including vue-apollo 4)

vknowles-rv avatar Jul 26 '22 14:07 vknowles-rv