vuejs / language-tools

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

vtsc mixing up event names declared in emits? #3493

Closed Arturexe closed 11 months ago

Arturexe commented 1 year ago

Vue version

3.3.4

Link to minimal reproduction

-

Steps to reproduce

i have no idea, create multiple emits?

What is expected?

vtsc should not fail.

What is actually happening?

I'm running vtsc on this vue component:

<script setup lang="ts">
import { reactive, watch } from 'vue'
import { DomainRobotModels } from 'js-domainrobot-sdk'
import {
  NameCode,
  KeyValue,
  ProductTreeStructure,
  CustomerProp,
} from '@/declarations'

import { useRouteStore } from '@/pinia/routeStore'
import ProductTabToggle from '@/components/products/product-tab-toggle.vue'
import ProductsTab from '@/components/products/products-tab.vue'
import ProductSettingsTab from '@/components/products/product-settings-tab.vue'

const routeStore = useRouteStore()

const props = defineProps<{
  customer?: CustomerProp
  query?: DomainRobotModels.Query
  checkedPriceClassNames?: string[]
  productsTab?: string
  priceSetting?: NameCode[]
  customerClients?: KeyValue[]
}>()

type State = {
  priceData: ProductTreeStructure
  filterTab: string
  search: string
  priceSetting: NameCode[]
  customerClients: KeyValue[]
  showAllBusinessCases: boolean
}

const state: State = reactive({
  priceData: {},
  search: '',
  filterTab: 'products',
  priceSetting: [{ name: 'Standardpreise', code: 'showStandardPrices' }],
  customerClients: [],
  showAllBusinessCases: false,
})

const emit = defineEmits<{
  (e: 'update:query', query?: DomainRobotModels.Query): void
  (e: 'submit', query?: DomainRobotModels.Query): void
  (
    e: 'update:checkedPriceClassNames',
    checkedPriceClassNames?: string | string[]
  ): void
  (e: 'update:priceSetting', priceSetting: NameCode[]): void
  (e: 'update:customerClients', customerClients: KeyValue[]): void
  (e: 'update:showAllBusinessCases', showAllBusinessCases: boolean): void
}>()

const emitShowAllBusinessCases = (event: boolean): void => {
  emit('update:showAllBusinessCases', event)
}

const emitCustomerClients = (event: KeyValue[] | undefined): void => {
  emit('update:customerClients', event)
}

const emitPriceSetting = (event: NameCode[] | undefined): void => {
  emit('update:priceSetting', event)
}

watch(
  () => props.productsTab,
  () => {
    state.search = ''
  }
)

if (props.customer) {
  watch(
    () => state.search,
    () => {
      routeStore.query.search = state.search
    }
  )
}

const resetFilter = () => {
  state.search = ''
}
</script>

<template>
  <div class="h-full min-h-[calc(100vh-6rem-1px)] bg-white rounded shadow-main">
    <div
      class="flex pt-4 px-5 mb-[35px] justify-between items-center uppercase text-[15px] text-gray-600 font-bold select-none">
      Filter
    </div>

    <product-tab-toggle
      :tabs="['products', 'settings']"
      v-model:activeTab="state.filterTab"
      stretch />

    <products-tab
      v-if="state.filterTab === 'products'"
      :productsTab="productsTab"
      @update:search="state.search = $event"
      @update:query="emit('update:query', $event)"
      @update:checkedPriceClassNames="
        emit('update:checkedPriceClassNames', $event)
      "
      @submit="emit('submit', $event)"
      @reset="resetFilter" />

    <product-settings-tab
      v-else
      :customer="customer"
      :productsTab="productsTab"
      :priceSetting="state.priceSetting"
      :customerClients="state.customerClients"
      :showAllBusinessCases="state.showAllBusinessCases"
      @update:priceSetting="emitPriceSetting"
      @update:customerClients="emitCustomerClients"
      @update:showAllBusinessCases="emitShowAllBusinessCases" />
  </div>
</template>

but these errors are thrown:

  The last overload gave the following error.
    Argument of type '"update:customerClients"' is not assignable to parameter of type '"update:showAllBusinessCases"'.

62   emit('update:customerClients', event)
          ~~~~~~~~~~~~~~~~~~~~~~~~

  src/components/products/product-filter.vue:54:3
    54   (e: 'update:showAllBusinessCases', showAllBusinessCases: boolean): void
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The last overload is declared here.

src/components/products/product-filter.vue:66:8 - error TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type '"update:priceSetting"' is not assignable to parameter of type '"update:showAllBusinessCases"'.

66   emit('update:priceSetting', event)
          ~~~~~~~~~~~~~~~~~~~~~

  src/components/products/product-filter.vue:54:3
    54   (e: 'update:showAllBusinessCases', showAllBusinessCases: boolean): void
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The last overload is declared here.

[11:29:55 AM] Found 2 errors. Watching for file changes.

It seems that vtsc is confusing the events declared in emit. I've already move the emits out of inline-events but it didn't help.

[11:29:55 AM] Found 2 errors. Watching for file changes.

System Info

The vue app is running inside a docker container:

  System:
    OS: Linux 5.15 Debian GNU/Linux 10 (buster) 10 (buster)
    CPU: (6) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 5.10 GB / 7.67 GB
    Container: Yes
    Shell: 5.0.3 - /bin/bash
  Binaries:
    Node: 16.20.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 8.19.4 - /usr/local/bin/npm
  npmPackages:
    vue: ^3.2.45 => 3.3.4

Any additional comments?

No response

Arturexe commented 1 year ago

I've removed the @update: event-prefixes and now the vtsc succeeds:

    <product-settings-tab
      v-else
      :customer="customer"
      :productsTab="productsTab"
      :showAllBusinessCases="state.showAllBusinessCases"
      :priceSetting="state.priceSetting"
      :customerClients="state.customerClients"
      @showAllBusinessCases="emit('update:showAllBusinessCases', $event)"
      @priceSetting="emit('update:priceSetting', $event)"
      @customerClients="emit('update:customerClients', $event)" />

Edit: This however leads to other issues with how the event is handled. It seems to be broken.

akash-melkeri commented 1 year ago

const emitShowAllBusinessCases = (event: boolean): void => { emit('update:showAllBusinessCases', event) } just before emit, can you log event and share it again ?

so1ve commented 11 months ago

@Arturexe priceSetting and customerClients's second argument cannot include undefined, but you did pass undefined.

const emit = defineEmits<{
  (e: 'update:customerClients', customerClients: KeyValue[] /* note this */): void
}>()

const emitCustomerClients = (event: KeyValue[] | undefined /* note this */): void => {
  emit('update:customerClients', event)
}
so1ve commented 11 months ago

(though the error message is a little bit weird)