Skip to content
Advertisement

Vue 3 defineEmits breaks defineProps types

I’m using Vue 3 and TS 4.4. I’ve got a component that defines its prop types with defineProps. When I add a call to defineEmits, VS Code starts telling me my props variable doesn’t exist in the component template. Here’s the source code:

<script setup lang="ts">
import { defineProps, defineEmits, VueElement, defineComponent } from "vue";

const emit = defineEmits<{
  "update:checked": boolean;
}>();

const props = defineProps<{
  label?: VueElement | string;
  checked?: boolean;
}>();
</script>

<template>
  <label>
    <input
      type="checkbox"
      :checked="props.checked"
      @change="(event) => emit('update:checked', (event.target as any)?.checked)"
    />
    {{ props.label }}
  </label>
</template>

And a couple of screenshots to better show what I’m seeing in VS Code. This is after adding defineEmits:

VS Code TS error

And this is without defineEmits:

VS Code without TS error

What is the correct way to define types for both props and emits?

Advertisement

Answer

The defineEmits<T>() generic argument is essentially a TypeScript interface that defines only functions, which receive a specific event name and optional arguments:

interface Emits {
  (e: __EVENT1_NAME__ [, arg1: __ARG1_TYPE__ [, arg2: __ARG2_TYPE__]]...): void
  (e: __EVENT2_NAME__ [, arg1: __ARG1_TYPE__ [, arg2: __ARG2_TYPE__]]...): void
}

Examples:

// as inline type
const emits = defineEmits<{
  (eventName: 'hover', hovering: boolean): void
  (eventName: 'changed', newValue: number, id: string): void
}>()
// as interface
interface Emits {
  (eventName: 'hover', hovering: boolean): void
  (eventName: 'changed', newValue: number, id: string): void
}
const emits = defineEmits<Emits>()
// as type alias
type Emits = {
  (eventName: 'hover', hovering: boolean): void
  (eventName: 'changed', newValue: number, id: string): void
}
const emits = defineEmits<Emits>()

For your update:checked event, the code should look similar to the following:

// as inline type
const emits = defineEmits<{
  (e: 'update:checked', checked: boolean): void
}>()
// as interface
interface Emits {
  (e: 'update:checked', checked: boolean): void
}
const emits = defineEmits<Emits>()
// as type alias
type Emits = {
  (e: 'update:checked', checked: boolean): void
}
const emits = defineEmits<Emits>()
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement