Subscribe on changes!

How to import emits interface

avatar
Nov 3rd 2023

Vue version

3.3.7

Link to minimal reproduction

https://play.vuejs.org/#eNp9k02P0zAQhv/K4EtasUpY7a2kFWxVCTgAAiQuvqTJtPWuY0f+KEVR/jtju21KtdtLlJl5Z+bxeNyzj12X7z2yGSttbUTnwKLz3YIr0XbaOOjB4AYG2BjdQkbS7Bxa6rY7+vMiGKFS9p4rrmqtrIPWbmEe8ifZJ5RSw29tZPMmm3JVFqkdNSLDYdvJyiFZAOXuftH3MXkYyoKs6I3dCvovi7Oc3TFnqddGbPMnqxUdow9izmpSC4nmW+cEsXA2gxgJsYpQ/nyJPmc83p389Q7r5xf8T/YQfJx9N2jR7JGzc8xVZosuhVc/v+KB/s/BVjdekvpG8AdaLX1gTLJHrxrCvtBF2s9x4kJtf9nVwaGyp0MF0KAcop4zuoEwqNeOPuI+5A8xj6uBphjGpW21lpg7S1PEQ7xhoRyaTVUjPFYWV61wNtaaYGCtd5XahmGAaGagfLtGM53BXosmVT3txPV2gaTEOdEQ3K1No1U6x0aAkyIvRuq0dSNuUtLAUTX2Cj7SZ14tI372Mv1phTGmzaHBjVCpSBm/i8n0YtNr7ZU77vq7/wJS1M+rPcboZArzRWKICfm+kh7h7Rzugy/2mmRprMR1oQklienWq1l757QC97dDGm2yOIMPkYA8IwkNfRlK0170R/Lw0FLK1QMb/gFe22bk

Steps to reproduce

Similar to issue #4294

component.ts: export interface Base { (e: "change", id: number): void }

Comp.vue import { Base } from ./component.ts

interface Emits extends Base { (e: "unChange", id: number): void } const emit = defineEmits()

emit(change, 1)

What is expected?

Component registers change as possible event, no errors/warnings raised.

What is actually happening?

[Vue warn]: Component emitted event "change" but it is neither declared in the emits option nor as an "onChange" prop.

System Info

No response

Any additional comments?

No response

avatar
Nov 6th 2023

You are using emit incorrectly. emit is used for child components to send events to their parent components. Therefore, you need to declare the change function in the parent component.

One more thing, you have defined an unchange function in the Emit interface. This means that in emits('func', value), you should use the same name, like emits('unChange', count.value).

The correct code is as follows:

Comp.vue

<script setup lang="ts">
import { ref } from 'vue'
import { BaseEmits } from './composable'

interface Emits extends BaseEmits {
  (e: 'unChange', id: number): void
}

const emits = defineEmits<Emits>()

const count = ref(0)

const clickEvent = () => {
  count.value += 1
  emits('unChange', count.value)
}
</script>

<template>
  <button type="button" @click="clickEvent">Count: {{ count }}</button>
</template>

App.vue

<script setup lang="ts">
import { ref } from 'vue'
import Comp from './components/Comp.vue'

const msg = ref('Hello World!')

const handleChange = () => {
  console.log('KUN IS THE CUTEST!')
  // Something code you want to execute here
}
</script>

<template>
  <h1>{{ msg }}</h1>
  <Comp @un-change="handleChange" />
</template>

BTW, In 3.3+, you can use more succinct syntax

const emit = defineEmits<{
  change: [id: number]
  update: [value: string]
}>()

see: https://vuejs.org/guide/typescript/composition-api.html#typing-component-emits

avatar
Nov 6th 2023

Code below seems to work

type Emits = BaseEmits  & {
  (e: 'unChange', id: number): void
}
avatar
Nov 6th 2023

Code below seems to work

type Emits = BaseEmits  & {
  (e: 'unChange', id: number): void
}

You're welcome! I didn't know about this usage either.

avatar
Nov 7th 2023

Before the fix gets merged, you can use https://github.com/unplugin/unplugin-vue-complex-types as a temporal solution.

avatar
Nov 9th 2023

Closing as duplicate of #8465, tracking there