--- title: Always Explicitly Type Event Handlers impact: MEDIUM impactDescription: Without explicit typing, event parameters have implicit 'any' type causing TypeScript errors in strict mode type: gotcha tags: [vue3, typescript, events, dom-events, composition-api] --- # Always Explicitly Type Event Handlers **Impact: MEDIUM** - Native DOM event handlers in Vue components have implicit `any` type for the `event` parameter. In TypeScript strict mode, this causes errors. You must explicitly type event parameters and use type assertions for `event.target`. ## Task Checklist - [ ] Always type the `event` parameter explicitly (e.g., `Event`, `MouseEvent`) - [ ] Use type assertions when accessing element-specific properties - [ ] Consider using inline handlers for simple cases - [ ] Be aware of Vue's synthetic event system ## The Problem ```vue ``` ## The Solution ```vue ``` ## Common Event Types | Event | Type | Common Properties | |-------|------|-------------------| | click, dblclick | `MouseEvent` | clientX, clientY, button | | keydown, keyup, keypress | `KeyboardEvent` | key, code, ctrlKey, shiftKey | | input, change | `Event` | target (needs assertion) | | focus, blur | `FocusEvent` | relatedTarget | | submit | `SubmitEvent` | submitter | | drag, dragstart, drop | `DragEvent` | dataTransfer | | wheel, scroll | `WheelEvent` | deltaX, deltaY | | touch events | `TouchEvent` | touches, changedTouches | ## Element-Specific Type Assertions ```vue ``` ## Inline Event Handler Pattern For simple cases, inline handlers with type annotations work well: ```vue ``` ## Generic Handler Pattern Create reusable typed handlers: ```typescript // utils/events.ts export function getInputValue(event: Event): string { return (event.target as HTMLInputElement).value } export function getSelectValue(event: Event): string { return (event.target as HTMLSelectElement).value } export function getCheckboxChecked(event: Event): boolean { return (event.target as HTMLInputElement).checked } ``` ```vue ``` ## Vue Component Events For Vue component events (not DOM events), use `defineEmits` for type safety: ```vue ``` ## Avoiding currentTarget vs target Confusion ```typescript function handleClick(event: MouseEvent) { // target: The element that triggered the event (could be a child) const target = event.target as HTMLElement // currentTarget: The element the listener is attached to const currentTarget = event.currentTarget as HTMLButtonElement // Be explicit about which you need if (target.tagName === 'SPAN') { // Clicked on span inside button } } ``` ## Reference - [Vue.js TypeScript with Composition API - Event Handlers](https://vuejs.org/guide/typescript/composition-api.html#typing-event-handlers) - [MDN Event Reference](https://developer.mozilla.org/en-US/docs/Web/Events) - [TypeScript DOM Types](https://github.com/microsoft/TypeScript/blob/main/lib/lib.dom.d.ts)