In Vue 3, events not declared in the emits option are not recognized as component events. Vue’s attribute fallthrough instead attaches
the parent’s v-on listener to the component’s root element as a native DOM event listener. This makes the component’s event API implicit,
and when an undeclared event name matches a native DOM event (such as submit or click), the handler can fire twice: once
from $emit() and once from the native DOM event.
Explicitly declaring events in emits prevents fallthrough, documents which events the component can raise, and makes the component’s
API clear to consumers.
To fix the issue, list every emitted event in the emits option. In <script setup> components, use
defineEmits instead.
<script>
export default {
methods: {
submit() {
this.$emit('submit'); // Noncompliant: "submit" is not declared in emits
}
}
}
</script>
<script>
export default {
emits: ['submit'],
methods: {
submit() {
this.$emit('submit');
}
}
}
</script>
<script setup lang="ts">
const emit = defineEmits<{ submit: [] }>();
function cancel() {
emit('cancel'); // Noncompliant: "cancel" is not declared in defineEmits
}
</script>
<script setup lang="ts">
const emit = defineEmits<{ submit: []; cancel: [] }>();
function cancel() {
emit('cancel');
}
</script>