Vue.js course Β· Module 15: TypeScript & Nuxt
Typing Props
In this lesson5
In the Quantum Laboratory, every station module must precisely declare what data it accepts. In Vue 3 with TypeScript, we use the generic syntax defineProps<{}>() to type props.
defineProps with Generic Type
Instead of runtime validation (object with type, required), we can use TypeScript syntax:
1<script setup lang="ts">
2// Generic syntax - types checked at compile time
3const props = defineProps<{
4 title: string
5 count: number
6 isActive: boolean
7}>()
8</script>This is equivalent to the traditional syntax:
1<script setup>
2// Old syntax - runtime validation
3const props = defineProps({
4 title: { type: String, required: true },
5 count: { type: Number, required: true },
6 isActive: { type: Boolean, required: true }
7})
8</script>Extracting an Interface
When a component has many props, it's worth extracting an interface:
1<script setup lang="ts">
2interface StationModuleProps {
3 name: string
4 status: 'online' | 'offline' | 'maintenance'
5 powerLevel: number
6 crew?: string[] // optional prop (?)
7}
8
9const props = defineProps<StationModuleProps>()
10</script>The ? sign means the prop is optional - it doesn't have to be passed.
withDefaults
TypeScript generics don't allow default values in defineProps. That's what withDefaults is for:
1<script setup lang="ts">
2interface PanelProps {
3 title: string
4 variant?: 'primary' | 'danger' | 'success'
5 maxItems?: number
6 showHeader?: boolean
7}
8
9const props = withDefaults(defineProps<PanelProps>(), {
10 variant: 'primary',
11 maxItems: 10,
12 showHeader: true
13})
14</script>Now props.variant will be 'primary' if not provided.
Union Types in Props
TypeScript allows defining precise types:
1<script setup lang="ts">
2type AlertLevel = 'info' | 'warning' | 'critical'
3
4interface AlertProps {
5 level: AlertLevel
6 message: string
7 code?: number
8}
9
10const props = defineProps<AlertProps>()
11</script>
12
13<template>
14 <div :class="['alert', props.level]">
15 {{ props.message }}
16 </div>
17</template>Complex Prop Types
Props can contain nested objects and arrays:
1<script setup lang="ts">
2interface Coordinate {
3 x: number
4 y: number
5 z: number
6}
7
8interface SensorData {
9 id: string
10 location: Coordinate
11 readings: number[]
12 metadata?: Record<string, unknown>
13}
14
15interface SensorPanelProps {
16 sensors: SensorData[]
17 selectedId: string | null
18 onSelect?: (id: string) => void
19}
20
21const props = defineProps<SensorPanelProps>()
22</script>Record<string, unknown> is a dictionary type - an object with string keys and values of any type.
Code for this lesson: App.vue
1<script setup lang="ts">
2import { ref } from 'vue'
3import ModuleCard from './ModuleCard.vue'
4
5interface StationModule {
6 id: string
7 name: string
8 status: 'online' | 'offline' | 'maintenance'
9 power: number
10}
11
12const modules = ref<StationModule[]>([
13 { id: 'm1', name: 'Life Support', status: 'online', power: 95 },
14 { id: 'm2', name: 'Navigation', status: 'online', power: 88 },
15 { id: 'm3', name: 'Science Lab', status: 'maintenance', power: 40 },
16 { id: 'm4', name: 'Communications', status: 'offline', power: 0 }
17])
18</script>
19
20<template>
21 <div class="nova-lab">
22 <h1>NOVA LAB - Typed Props</h1>
23 <ModuleCard
24 v-for="mod in modules"
25 :key="mod.id"
26 :module="mod"
27 :show-power="true"
28 />
29 </div>
30</template>
31
32<style scoped>
33.nova-lab {
34 background: #0a0e27;
35 color: #00ff88;
36 min-height: 100vh;
37 padding: 20px;
38 font-family: monospace;
39}
40h1 { color: #00ff88; margin-bottom: 15px; }
41</style>Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. Which syntax defines typed props in Vue 3 with TypeScript?
2. How do you mark a prop as optional in a TypeScript interface?
These are 2 of 3 questions for this lesson. Solve the rest in the game.
Hands-on tasks in the game
- Code editor
Use withDefaults(defineProps<Props>(), { ... }) to set default values.
- Horizontal ordering
Arrange the correct withDefaults syntax with defineProps:
- Code editor
Use defineEmits<{}> to define a 'command' event with typed arguments.