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 407 forks source link

Suspected TypeScript bug when globally registering component that uses script tag generics with defineModel #4822

Closed TristanMNorton closed 1 month ago

TristanMNorton commented 2 months ago

Vue - Official extension or vue-tsc version

2.1.6

VSCode version

1.93.0

Vue version

3.5.3

TypeScript version

5.5.3

System Info

System:
    OS: macOS 14.5
    CPU: (14) arm64 Apple M3 Max
    Memory: 642.34 MB / 36.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.15.1 - ~/.nvm/versions/node/v20.15.1/bin/node
    npm: 10.7.0 - ~/.nvm/versions/node/v20.15.1/bin/npm

package.json dependencies

{
  "name": "generics-test",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc -b && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "vue": "^3.5.3"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^5.1.2",
    "typescript": "^5.5.3",
    "vite": "^5.4.1",
    "vue-tsc": "^2.1.6"
  }
}

Steps to reproduce

Main.ts

import { createApp } from 'vue'
import App from './App.vue'
import HelloWorld from './components/HelloWorld.vue'

const app = createApp(App)

app.mount('#app')

app.component('HelloWorld', HelloWorld) // Typescript error

HelloWorld.vue

<script setup lang="ts" generic="T">
const modelValue = defineModel<T>()
</script>

<template>
  <pre>
    {{ modelValue }}
  </pre>
</template>

What is expected?

The SFC internally is type safe and should allow for usage of generics when using defineModel.

What is actually happening?

Argument of type '<T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<...>) => VNode<...> & { ...; }' is not assignable to parameter of type 'Component<any, any, any, ComputedOptions, MethodOptions, {}, any> | DefineComponent<{}, {}, {}, ComputedOptions, MethodOptions, ... 14 more ..., any>'.
  Type '<T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<...>) => VNode<...> & { ...; }' is not assignable to type 'FunctionalComponent<any, {}, any, {}>'.
    Types of parameters '__VLS_ctx' and 'ctx' are incompatible.
      Type 'Omit<{ attrs: Data; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed | undefined) => void; }, "expose">' is not assignable to type '{ slots: {}; attrs: any; emit: __VLS_ModelEmitsType; }'.
        Types of property 'emit' are incompatible.
          Type '(event: string, ...args: any[]) => void' is not assignable to type '__VLS_ModelEmitsType'.ts(2345)

Link to minimal reproduction

No response

Any additional comments?

I at least suspect this is an issue with vue-tsc. I can't reproduce with Vue SFC Playground as I don't have access to the main typescript file.

throrin19 commented 2 months ago

Same problem here. I have component who works fine and I move all models usage using defineModeland now I have this TS Error when I made a globalComponent with app.component :

L'argument de type '<T extends ({ id: string | number; } | Model)>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<...>) =>...' n'est pas attribuable au paramètre de type 'Component<any, any, any, ComputedOptions, MethodOptions, {}, any> | DefineComponent<{}, {}, {}, ComputedOptions, MethodOptions, ... 14 more ..., any>'.
  Impossible d'assigner le type '<T extends ({ id: string | number; } | Model)>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<...>) =>...' au type 'FunctionalComponent<any, {}, any, {}>'.
    Les types des paramètres '__VLS_ctx' et 'ctx' sont incompatibles.
      Impossible d'assigner le type 'Omit<{ attrs: Data; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed | undefined) => void; }, "expose">' au type '{ slots: {}; attrs: any; emit: ((evt: "fire:event", event: string, item: any) => void) & __VLS_ModelEmitsType; }'.
        Les types de la propriété 'emit' sont incompatibles.
          Impossible d'assigner le type '(event: string, ...args: any[]) => void' au type '((evt: "fire:event", event: string, item: any) => void) & __VLS_ModelEmitsType'.
            Impossible d'assigner le type '(event: string, ...args: any[]) => void' au type '__VLS_ModelEmitsType'.ts(2345)

The problem seems to come from the emit part, which doesn't seem to want the __VLS_ModelEmitsType type introduced by defineModel.