Props/Emits Typing
11.2.1. defineProps Typing
Props must be typed using the generic syntax defineProps<T>(). The runtime declaration approach must not be used.
vue
<script setup lang="ts">
defineProps<{
title: string
count: number
isActive: boolean
}>()
</script>When props exceed 3 properties, extract them into a separate interface.
vue
<script setup lang="ts">
interface UserCardProps {
userId: number
name: string
email: string
role: string
avatarUrl?: string
}
const props = defineProps<UserCardProps>()
</script>11.2.2. withDefaults
Default values for props must use withDefaults. Default values for object or array types must use a factory function.
vue
<script setup lang="ts">
interface NotificationProps {
message: string
type?: 'info' | 'warning' | 'error'
duration?: number
actions?: string[]
}
const props = withDefaults(defineProps<NotificationProps>(), {
type: 'info',
duration: 3000,
actions: () => [],
})
</script>- Primitive types (string, number, boolean) must have their values assigned directly.
- Object and array types must use factory functions to prevent shared references across instances.
11.2.3. defineEmits Typing
Emits must define event signatures using the generic syntax. Payload types must be explicitly specified.
vue
<script setup lang="ts">
const emit = defineEmits<{
search: [filters: { keyword: string; category: string }]
reset: []
select: [id: number, label: string]
}>()
function handleSearch(keyword: string, category: string) {
emit('search', { keyword, category })
}
</script>- Events without a payload must be defined with an empty array
[]. - When a payload has 2 or more parameters, labels must be provided for readability.
11.2.4. Complex Props Patterns
Union Props are used to branch component behavior modes.
vue
<script setup lang="ts">
type ButtonProps =
| { variant: 'link'; href: string; disabled?: boolean }
| { variant: 'button'; onClick: () => void; disabled?: boolean }
const props = defineProps<ButtonProps>()
</script>v-model Props must be defined as a modelValue and update:modelValue pair.
vue
<script setup lang="ts">
const props = defineProps<{ modelValue: string; placeholder?: string }>()
const emit = defineEmits<{ 'update:modelValue': [value: string] }>()
</script>Conditionally required Props follow a pattern where different properties become required depending on a discriminant property.
vue
<script setup lang="ts">
type ModalProps =
| { mode: 'confirm'; onConfirm: () => void; onCancel: () => void }
| { mode: 'alert'; onConfirm: () => void }
const props = defineProps<ModalProps>()
</script>- When union Props become excessively complex, consider splitting into separate components.