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

TypeScript with Vue.js

2 min read
In this lesson5

Welcome to the NOVA LAB Quantum Laboratory! Year 2087 - the space station systems demand the highest precision. Any error in a data type could lead to a catastrophe. That's why our engineers use TypeScript - a static type system that catches errors before the code even runs.

Why TypeScript with Vue?

TypeScript is a superset of JavaScript that adds static types. Combined with Vue 3, it gives us:

  • Autocompletion in the code editor (IntelliSense)
  • Error detection before running the application
  • Better documentation - types describe the shape of data
  • Refactoring - the editor understands the code structure

Setting Up a Vue Project with TypeScript

Creating a Vue project with TypeScript is simple thanks to Vite:

1npm create vite@latest nova-lab -- --template vue-ts

Vite automatically configures TypeScript and creates a tsconfig.json file:

1{
2  "compilerOptions": {
3    "target": "ES2020",
4    "module": "ESNext",
5    "moduleResolution": "bundler",
6    "strict": true,
7    "jsx": "preserve",
8    "paths": {
9      "@/*": ["./src/*"]
10    }
11  },
12  "include": ["src/**/*.ts", "src/**/*.vue"]
13}

The lang="ts" Attribute

In Vue SFC (Single File Components), we add lang="ts" to the <script setup> block:

1<script setup lang="ts">
2import { ref } from 'vue'
3
4const stationName = ref<string>('NOVA LAB')
5const crewCount = ref<number>(42)
6const isOnline = ref<boolean>(true)
7</script>

Without lang="ts", Vue treats the code as plain JavaScript. With lang="ts", the TypeScript compiler checks types and catches errors.

Basic Types in Vue

1<script setup lang="ts">
2import { ref } from 'vue'
3
4// Simple types
5const name: string = 'Mars Station'
6const year: number = 2087
7const active: boolean = true
8
9// Arrays
10const modules: string[] = ['Lab', 'Hangar', 'Bridge']
11const temperatures: number[] = [-63, -58, -71]
12
13// Ref with generic type
14const status = ref<string>('operational')
15const energy = ref<number>(98.5)
16</script>

TypeScript automatically infers types, so you don't always have to specify them explicitly:

1const count = ref(0)       // ref<number> - inferred automatically
2const label = ref('test')  // ref<string> - inferred automatically

Explicit typing is useful when the type cannot be inferred:

1const data = ref<string | null>(null)  // can be string or null

TypeScript Interfaces

Interfaces define the shape of objects:

1interface CrewMember {
2  id: number
3  name: string
4  role: string
5  active: boolean
6}
7
8const engineer: CrewMember = {
9  id: 1,
10  name: 'Dr. Nova',
11  role: 'Chief Engineer',
12  active: true
13}
Code for this lesson: App.vue
1<script setup lang="ts">
2import { ref } from 'vue'
3
4// Basic types
5const stationName = ref<string>('NOVA LAB')
6const crewCount = ref<number>(42)
7const isOnline = ref<boolean>(true)
8
9// Interface
10interface CrewMember {
11  id: number
12  name: string
13  role: string
14  active: boolean
15}
16
17// Typed array
18const crew = ref<CrewMember[]>([
19  { id: 1, name: 'Dr. Nova', role: 'Commander', active: true },
20  { id: 2, name: 'Atlas', role: 'Navigator', active: true },
21  { id: 3, name: 'Echo', role: 'Engineer', active: false }
22])
23
24// Union type
25const status = ref<'online' | 'offline' | 'maintenance'>('online')
26
27function toggleStatus() {
28  const states: Array<'online' | 'offline' | 'maintenance'> = ['online', 'offline', 'maintenance']
29  const idx = states.indexOf(status.value)
30  status.value = states[(idx + 1) % states.length]
31}
32</script>
33
34<template>
35  <div class="nova-lab">
36    <h1>{{ stationName }}</h1>
37    <p>Crew: {{ crewCount }} | Status: <span :class="status">{{ status }}</span></p>
38    <button @click="toggleStatus" class="btn">Toggle status</button>
39
40    <h2>Crew</h2>
41    <div v-for="member in crew" :key="member.id" class="card">
42      <strong>{{ member.name }}</strong> - {{ member.role }}
43      <span :class="member.active ? 'active' : 'inactive'">
44        {{ member.active ? 'Active' : 'Inactive' }}
45      </span>
46    </div>
47  </div>
48</template>
49
50<style scoped>
51.nova-lab {
52  background: #0a0e27;
53  color: #00ff88;
54  min-height: 100vh;
55  padding: 20px;
56  font-family: monospace;
57}
58h1 { color: #00ff88; margin-bottom: 5px; }
59h2 { color: #00b4d8; margin-top: 20px; }
60.btn {
61  background: #00b4d8;
62  color: white;
63  border: none;
64  padding: 8px 16px;
65  border-radius: 8px;
66  cursor: pointer;
67  margin: 10px 0;
68}
69.card {
70  background: rgba(0, 180, 216, 0.1);
71  border: 1px solid #00b4d8;
72  padding: 12px 16px;
73  margin: 6px 0;
74  border-radius: 8px;
75  display: flex;
76  justify-content: space-between;
77  align-items: center;
78}
79.online { color: #00ff88; }
80.offline { color: #e74c3c; }
81.maintenance { color: #f39c12; }
82.active { color: #00ff88; font-size: 12px; }
83.inactive { color: #e74c3c; font-size: 12px; }
84</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. What is the main benefit of using TypeScript with Vue.js?

  2. 2. What attribute do we add to the <script setup> block to enable TypeScript?

These are 2 of 3 questions for this lesson. Solve the rest in the game.

Hands-on tasks in the game

  • Code editor

    Type ref as string, number, boolean and create an interface for a crew object.

  • Click in order

    Arrange the steps for configuring a Vue project with TypeScript:

  • Code editor

    Define a ModuleProps interface and use defineProps with a generic type.

Useful articles