Deepen your Vue 3 Composition API vocabulary — typed injection, composable conventions, shallow reactivity, and defineModel.
0 / 5 completed
1 / 5
During standup, the team discusses typed dependency injection with InjectionKey in Vue 3. What is it?
InjectionKey<T> is created with Symbol() as InjectionKey<T>. When you provide(key, value) and inject(key), TypeScript infers the type T automatically — no casting needed. Without a typed symbol, inject() returns T | undefined with unknown type.
2 / 5
In a PR review, the team debates composable return conventions in Vue 3. What's the recommended pattern?
The Vue 3 convention is to return raw refs from composables — { count, increment } where count is a Ref<number>. Callers can destructure without losing reactivity because refs maintain their reactive link. In templates, Vue auto-unwraps refs, so {{ count }} works without .value.
3 / 5
An incident involves stale timers from watchEffect not cleaning up. How do you handle cleanup?
watchEffect provides an onCleanup callback parameter. Register your teardown logic there: watchEffect((onCleanup) => { const id = setTimeout(...); onCleanup(() => clearTimeout(id)); }). Vue calls onCleanup before the effect re-runs due to dependency changes and when the component unmounts.
4 / 5
In a design review, the team chooses between shallowRef vs ref for a large configuration object. What's the difference?
shallowRef wraps the reference in reactivity but not the object's contents. Replacing shallowRef.value = newObj triggers updates; mutating shallowRef.value.someProperty does NOT. This avoids the performance cost of deeply Proxying large config objects, external libraries' data structures, or data that's always replaced wholesale.
5 / 5
During a code review, a teammate uses defineModel() macro in a Vue 3 component. What does it replace?
defineModel() (available in Vue 3.4+) replaces the defineProps(['modelValue']) + defineEmits(['update:modelValue']) boilerplate. It returns a ref you can read and write directly — writes automatically emit update:modelValue to the parent. This makes two-way binding components much cleaner to author.