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. 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.
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
- TypeScript Setup in Vue Projects
- Typed Props and Emits with defineProps/defineEmits
- Typing Composables and Refs
- Generic Vue Components