vuejs / language-tools

⚡ High-performance Vue language tooling based-on Volar.js
https://marketplace.visualstudio.com/items?itemName=Vue.volar
MIT License
5.87k stars 402 forks source link

Methods not found in Vue 2.7 when using Options API with props #4996

Open strokirk opened 1 week ago

strokirk commented 1 week ago

Vue - Official extension or vue-tsc version

2.1.10

VSCode version

1.95.1

Vue version

2.7.16

TypeScript version

5.6.3

System Info

System:
  OS: Linux 5.0 undefined
  CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
  Memory: 0 Bytes / 0 Bytes
  Shell: 1.0 - /bin/jsh
Binaries:
  Node: 18.20.3 - /usr/local/bin/node
  Yarn: 1.22.19 - /usr/local/bin/yarn
  npm: 10.2.3 - /usr/local/bin/npm
  pnpm: 8.15.6 - /usr/local/bin/pnpm

package.json dependencies

{
  "dependencies": {
    "vue": "2.7.16"
  },
  "devDependencies": {
    "typescript": "5.6.3",
    "vue-tsc": "2.1.10"
  }
}

Steps to reproduce

Using vue-tsc on a Vue 2 component using the options API, the component methods are not included as part of the instance type if props is also present in the same component. For example:

<script lang="ts">
export default {
  name: 'HelloWorld',
  props: {
    fooprop: { type: String },
  },
  data() {
    return {
      foodata: null,
    };
  }, 
  methods: {
    foomethod(event) {
      console.log('foomethod');
    },
  },
};
</script>

<template>
  <p @click="foomethod">{{ fooprop }} {{ foodata }}</h1>
</template>

What is expected?

No error should be shown.

What is actually happening?

src/components/HelloWorld.vue:26:16 - error TS2339: Property 'foomethod' does not exist on type 'Vue3Instance<{ foodata: any; }, Readonly<ExtractPropTypes<{ fooprop: { type: StringConstructor; }; }>>, Readonly<ExtractPropTypes<{ fooprop: { type: StringConstructor; }; }>>, {}, {}, true, ComponentOptionsBase<...>> & ... 5 more ... & Readonly<...>'.

26     <p @click="foomethod">{{ fooprop }} {{ foodata }}</h1>

Link to minimal reproduction

https://stackblitz.com/edit/vitejs-vite-bxhnjs?file=src%2Fcomponents%2FHelloWorld.vue

Any additional comments?

Workaround: Following the comment in https://github.com/vuejs/language-tools/issues/1850#issuecomment-1281618777, manually setting vueCompilerOptions.optionsWrapper seem to help:

{
  "vueCompilerOptions": {
    "optionsWrapper": [
      "(await import('@vue/runtime-dom')).defineComponent(",
      ")"
    ]
  }
}

However, as a drawback, you then get a Doctor warning: https://github.com/vuejs/language-tools/blob/master/extensions/vscode/src/features/doctor.ts#L120

❗ Unnecessary @vue/runtime-dom Vue 2.7 already includes JSX type definitions. You can remove the @vue/runtime-dom dependency from package.json:

rchl commented 1 week ago

It's not really what's causing the issue but the target option in tsconfig.json is supposed to be a number, not a string.

rchl commented 1 week ago

It looks like you need to set "strict": true in tsconfig.json to fix it.

I seem to recall there was some related non-strict issue but if it's only in 2.7 Vue types then I'm not sure if there is any chance of it being fixed.

strokirk commented 1 week ago

@rchl Thanks for the guidance, I figured something like that would be the case for Vue2.

Interestingly, adding "strict": true doesn't help in my production repo - methods are still missing, but I'm having a harder time making a proper minimal reproduction.