Typed Props and Emits with defineProps/defineEmits
Generic defineProps (), complex types, optional props, emit typing.
Typed Props and Emits with defineProps/defineEmits is a free Vue Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Vue Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
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.
Frequently asked questions
Is the “Typed Props and Emits with defineProps/defineEmits” lesson free?
Yes — the full text of “Typed Props and Emits with defineProps/defineEmits” is free to read here on the web, and the Vue Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Vue Academy course, upgrade to CoddyKit PRO.
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; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
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
- TypeScript Setup in Vue Projects
- Typed Props and Emits with defineProps/defineEmits
- Typing Composables and Refs
- Generic Vue Components