Vue 3 with TypeScript: Common Pitfalls to Avoid
Vue 3 has solid TypeScript support, but a few patterns lose type safety quietly. Here's what to watch for in props, refs, and emits.
Vue 3 has the best TypeScript story Vue has ever had — but a handful of patterns lose type safety in ways that look fine until you read the inferred types. Here are the ones I see most.
Always type props with defineProps
Use the generic form: defineProps<{ id: string; active?: boolean }>(). Avoid the runtime form ({ id: String, active: Boolean }) — it works but TypeScript only sees them as the broad String, Boolean types, not literal types.
If you need defaults, withDefaults(defineProps<...>(), { active: false }) preserves the typed shape and applies defaults at runtime.
Type ref values when they start undefined
ref(null) infers Ref<null>, which is rarely what you want. Use ref<User | null>(null) so TypeScript knows what the ref will hold once data arrives. The same applies to template refs: const inputEl = ref<HTMLInputElement | null>(null).
Type emits as a tuple
tsconst emit = defineEmits<{
(e: 'update:modelValue', value: string): void
(e: 'submit'): void
}>()This catches typos in event names and ensures the payload matches. Without typed emits, emit('typo', value) compiles fine and silently does nothing.
Composable return types
When a composable returns reactive state, return refs (or a reactive object), but return them in a stable shape across all branches. If one path returns { user, loading } and another returns { user, error, loading }, the inferred return type becomes a union and consumers have to narrow it. Pick one shape and always return it.
About the author

Richard Gamora
Fullstack developer based in the Philippines, working mostly with Laravel and Vue.js, with eight years of production experience across web and mobile.
More on Vue & Nuxt
January 28, 2026
Vue 3 Composition API: Patterns That Scale
The Composition API is more flexible than the Options API but easier to misuse. Here are the patterns that hold up as components grow.
January 21, 2026
Migrating from Vuex to Pinia: A Practical Guide
Pinia is now the recommended state library for Vue 3. Here's how to migrate from Vuex incrementally without breaking working code.
January 14, 2026
Nuxt 3 SSR vs SSG: How to Decide for Your Site
Nuxt 3 supports server rendering, static generation, and hybrid modes per route. Here's a clear way to choose for content sites, SaaS apps, and marketing pages.