Vue Academy · Lesson

Typed Props and Emits with defineProps/defineEmits

Generic defineProps (), complex types, optional props, emit typing.

Lesson 2 of 413 steps

Typed Props and Emits with defineProps/defineEmits is a free Vue Academy lesson on CoddyKit. This is lesson 2 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Vue Academy learning path, and your progress syncs across the web and the CoddyKit app. The Vue Academy course includes 4 lessons in total.

Typing Component Inputs and Outputs

With lang="ts", the defineProps and defineEmits macros accept TypeScript types directly. This gives compile-time checks on what data flows in and out of a component.

Props From an Interface

Pass a type to the defineProps generic. An interface keeps complex prop shapes readable and reusable.

<script setup lang="ts">
interface Props {
  title: string
  count: number
}
const props = defineProps<Props>()
</script>

Inline Type Literals

For small components an inline object type is fine — no separate interface needed.

<script setup lang="ts">
const props = defineProps<{
  label: string
  disabled: boolean
}>()
</script>

Optional Properties With ?

Mark a property optional with ?. Optional props are typed as T | undefined and the parent may omit them.

<script setup lang="ts">
interface Props {
  title: string
  subtitle?: string
}
const props = defineProps<Props>()
</script>

Complex Prop Types

Props can be arrays, unions, or object shapes — anything TypeScript can express.

<script setup lang="ts">
interface Props {
  items: string[]
  size: 'sm' | 'md' | 'lg'
  user: { id: number; name: string }
}
const props = defineProps<Props>()
</script>

Defaults With withDefaults

The type-only form cannot hold defaults, so wrap it in withDefaults. The second argument maps prop names to default values.

<script setup lang="ts">
const props = withDefaults(defineProps<{
  size?: string
  count?: number
}>(), {
  size: 'md',
  count: 0
})
</script>

Defaults for Objects and Arrays

Object and array defaults must be returned from a factory function, just as in the Options API, to avoid sharing one instance across components.

withDefaults(defineProps<{
  tags?: string[]
}>(), {
  tags: () => []
})

Declaring Typed Emits

defineEmits can take a type that lists each event and its payload as a call signature. This catches wrong payload types at compile time.

<script setup lang="ts">
const emit = defineEmits<{
  (e: 'change', value: string): void
  (e: 'delete', id: number): void
}>()
</script>

Emitting Typed Payloads

Now emit only accepts valid event names and matching payload types. Passing a number where a string is expected is a compile error.

function rename(name: string) {
  emit('change', name) // ok
  // emit('change', 123) // type error
}

The Named Tuple Syntax

Vue 3.3+ supports a shorthand object form where each event maps to a tuple of its argument types — cleaner than call signatures.

<script setup lang="ts">
const emit = defineEmits<{
  change: [value: string]
  delete: [id: number]
}>()
</script>

Props and Emits Together

A typical typed component declares both: inputs via defineProps and outputs via defineEmits, fully checked end to end.

<script setup lang="ts">
defineProps<{ modelValue: string }>()
const emit = defineEmits<{
  'update:modelValue': [value: string]
}>()
</script>

Quick Check

Test your knowledge of typed props and emits.

Recap

You learned typed component I/O:

  • Pass an interface or inline type to defineProps<T>().
  • Use ? for optional props and withDefaults for defaults (factory for objects/arrays).
  • defineEmits<T>() types event names and payloads.
  • The tuple form (event: [payload]) is the modern shorthand.
Free to start

Learn HTML with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
42
Lessons
156

Frequently Asked Questions

Is the “Typed Props and Emits with defineProps/defineEmits” lesson free?

Yes — any 3 lessons of the Vue Academy learning path, including “Typed Props and Emits with defineProps/defineEmits”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Vue Academy course includes 4 lessons in total.

What will I learn in “Typed Props and Emits with defineProps/defineEmits”?

Generic defineProps (), complex types, optional props, emit typing. You practise Vue Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Vue Academy?

No prior experience is required. Vue Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 2 of 4.

How long does the “Typed Props and Emits with defineProps/defineEmits” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Vue Academy lesson?

Yes. Every Vue Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. TypeScript Setup in Vue Projects
  2. Typed Props and Emits with defineProps/defineEmits
  3. Typing Composables and Refs
  4. Generic Vue Components
← Back to Vue Academy