Files

4.6 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Use Event Validation for Complex Payloads LOW Event validation catches payload errors early with console warnings during development best-practice
vue3
emits
defineEmits
validation
debugging

Use Event Validation for Complex Payloads

Impact: LOW - Vue allows you to validate event payloads using object syntax for defineEmits. When a validation function returns false, Vue logs a console warning. This helps catch bugs early during development, especially for events with complex payload requirements.

Task Checklist

  • Use object syntax for defineEmits when validation is needed
  • Return true for valid payloads, false for invalid
  • Add meaningful console warnings in validators
  • Consider TypeScript for compile-time validation instead

Basic Validation

Using object syntax with validators:

<script setup>
const emit = defineEmits({
  // No validation - just declaration
  cancel: null,

  // Validate that email is present
  submit: (payload) => {
    if (!payload || !payload.email) {
      console.warn('Submit event requires an email field')
      return false
    }
    if (!payload.email.includes('@')) {
      console.warn('Submit event requires a valid email')
      return false
    }
    return true
  },

  // Validate ID is a number
  select: (id) => {
    if (typeof id !== 'number') {
      console.warn('Select event requires a numeric ID')
      return false
    }
    return true
  }
})

function handleSubmit(formData) {
  // If validation fails, Vue logs warning but event still emits
  emit('submit', formData)
}
</script>

What Happens on Validation Failure

<script setup>
const emit = defineEmits({
  submit: (data) => {
    if (!data?.email) {
      return false  // Validation fails
    }
    return true
  }
})

function badSubmit() {
  emit('submit', {})  // Missing email
  // Console: [Vue warn]: Invalid event arguments: event validation failed for event "submit"
  // Event STILL fires - validation is advisory only
}
</script>

Important: Validation failure only logs a warning. The event still emits. This is intentional for development debugging, not runtime enforcement.

Common Validation Patterns

Required Fields

const emit = defineEmits({
  'user-created': (user) => {
    const required = ['id', 'name', 'email']
    const missing = required.filter(field => !user?.[field])
    if (missing.length) {
      console.warn(`user-created missing fields: ${missing.join(', ')}`)
      return false
    }
    return true
  }
})

Type Checking

const emit = defineEmits({
  'page-change': (page) => typeof page === 'number' && page > 0,

  'items-selected': (items) => Array.isArray(items),

  'filter-applied': (filter) => {
    return filter && typeof filter.field === 'string' && filter.value !== undefined
  }
})

Range Validation

const emit = defineEmits({
  'rating-change': (rating) => {
    if (typeof rating !== 'number' || rating < 1 || rating > 5) {
      console.warn('Rating must be a number between 1 and 5')
      return false
    }
    return true
  }
})

TypeScript Alternative

For compile-time validation, prefer TypeScript types over runtime validators:

<script setup lang="ts">
interface SubmitPayload {
  email: string
  password: string
  rememberMe?: boolean
}

const emit = defineEmits<{
  submit: [payload: SubmitPayload]
  cancel: []
  'page-change': [page: number]
}>()

// TypeScript catches errors at compile time
emit('submit', { email: 'test@test.com' })
// Error: Property 'password' is missing
</script>

TypeScript validation is:

  • Caught at compile time, not runtime
  • Provides IDE autocompletion
  • Zero runtime overhead

When to Use Runtime Validation

Use object syntax validation when:

  • You're not using TypeScript
  • You need to validate values that can't be expressed in types (ranges, formats)
  • You want runtime debugging help during development
  • You're building a component library and want helpful dev warnings

Combining Both Approaches

<script setup lang="ts">
interface FormData {
  email: string
  age: number
}

// TypeScript handles type structure
// Runtime validator handles value constraints
const emit = defineEmits({
  submit: (data: FormData) => {
    if (data.age < 0 || data.age > 150) {
      console.warn('Age must be between 0 and 150')
      return false
    }
    if (!data.email.includes('@')) {
      console.warn('Invalid email format')
      return false
    }
    return true
  }
})
</script>

Reference