Vue.js course Β· Module 15: TypeScript & Nuxt

Typing Props

2 min read
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. 1. Which syntax defines typed props in Vue 3 with TypeScript?

  2. 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.

Useful articles