Skip to content

Chapter 2 of 6

TypeScript and Component Definition

Type safety and clean APIs become essential as Vue apps grow, and Vue provides several helpers for both at the component boundary. Wrapping a component with defineComponent() improves TypeScript inference across props, emits, computed values, and option fields, which pays off the moment any consumer of the component is itself typed. For complex prop shapes such as arrays of objects or discriminated unions, the PropType<T> helper lets you describe types in the Options API in a way the compiler understands. Inside <script setup>, the compiler macros defineProps() and defineEmits() declare props and event signatures with concise syntax, while defineExpose() explicitly exposes selected methods or refs to a parent that uses a template ref.

Clear event contracts matter as much as types. Beyond declaring what events a component can emit, you can attach validation functions to the emits option keyed by event name, so invalid payloads surface as warnings during development. When a parent uses v-model with modifiers such as .capitalize, Vue generates a modelModifiers prop on the child; reading that prop and branching on its flags lets the child apply the right behavior, such as transforming the value before emitting it back. Slot APIs follow a similar pattern of explicitness. On the parent side, you can destructure slot props with v-slot="{ item, index }" or the shorter #default="{ item, index }" so a component binds only the values it actually consumes.

Some tools are aimed at framework and library authors more than everyday app developers. getCurrentInstance() returns the currently active component instance, which is mostly useful when building plugins, render-function libraries, or other advanced internals where you need to reach into Vue's machinery. For most day-to-day code, registering things globally through the application instance keeps the surface area familiar: app.component('MyName', MyComponent) makes a component available everywhere in the app, while app.directive('focus', { mounted(el) { el.focus(); } }) installs a custom directive that Vue applies wherever you write v-focus. These patterns keep registration in one place and components themselves free of registration ceremony.

All chapters
  1. 1Reactivity Essentials
  2. 2TypeScript and Component Definition
  3. 3Built-in Components and Rendering
  4. 4Transitions and List Rendering
  5. 5Routing, State Management, and SSR
  6. 6Debugging, Performance, and Testing

Drill it

Reading is not remembering. These come from the Vue Cards deck:

Q

What is <code>shallowReactive</code> in Vue?

It creates a reactive object where only the top-level properties are tracked; nested objects stay non-reactive unless wrapped separately.

Q

What is <code>triggerRef()</code> used for?

It manually notifies Vue that a shallowRef changed after you mutated its inner value without replacing the reference.

Q

What does <code>getCurrentInstance()</code> return?

It returns the current active component instance and is mainly useful in advanced framework or library code.

Q

What is <code>Vue.compile()</code>?

It is a runtime+compiler API that turns a template string into a render function at runtime.