Type checking and editor setup
Vite strips types without checking them, so check them yourself with Vue - Official in the editor and vue-tsc on TypeScript 6 in the build and in CI.
What you'll learn
When you finish, you can do these.- 1Make a type error fail the build with vue-tsc
- 2Explain what each of the three tsconfig files covers
- 3Handle a list item TypeScript says may be undefined
- 4Stay on TypeScript 6 and set up VS Code for Vue
Picture a shop app made with create-vue, the official tool that starts a Vue project on your computer. Its heading greets the user with user.name, and a type says what a user has: a name and an email. Mistype user.name as user.nmae, and the tools that run the app say nothing. npm run dev, which shows the app while you work, keeps serving the page: "Hello", then nothing. vite build, which makes the files you publish, finishes without a word.
The Code tab holds that project's setup: package.json with its scripts, three tsconfig files with TypeScript's settings, and src/App.vue, the greeting page. By the end, the typo gets a red underline in your editor and fails npm run build. The rest of this track runs in a browser playground that cannot show type errors, so this lesson comes first. You need one idea from the lesson Events and v-model, in the Beginner track: in <script setup lang="ts">, a type is a label, such as number, that says what a value may hold.
Vite strips types, vue-tsc checks them
A typo like user.nmae fails the build only when a tool reads your types. Here is the part of src/App.vue, in the Code tab, that greets the user:
<script setup lang="ts">
interface User { name: string; email: string }
const user: User = { name: 'Ada', email: 'ada@example.com' }
</script>
<template>
<h1>Hello {{ user.name }}</h1>
</template>
interface User names a type: a user has a name and an email, both strings (text). const user: User says user must fit it, so TypeScript knows that user.nmae does not exist.
Vite, the build tool behind npm run dev and vite build, compiles each file on its own. It deletes the types you wrote and keeps the JavaScript, which is called stripping types. That keeps Vite fast, so a type error stops neither of them.
Two other tools read your types: one in your editor as you type, one in the terminal and in CI, the server that checks every push.
- Save a .vue file
- Vue - Officialthe editor, as you type
- vue-tsc --buildtype-check script and CI
- vite buildstrips types, never checks
In VS Code, the Vue - Official extension checks templates too, so user.nmae gets a red underline. vue-tsc checks the whole project. It is the TypeScript compiler, tsc, taught to read .vue files.
package.json, in the Code tab, holds the scripts that npm run starts:
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build"
}
run-p, from the npm-run-all2 package, runs type-check and build-only side by side. With the typo, build-only still writes dist/, the folder you publish. But type-check prints Property 'nmae' does not exist on type 'User'. That makes npm run build fail, so a CI job that runs it goes red.
Three tsconfig files
TypeScript reads its settings from a tsconfig.json file: which files to check, and how strictly. A create-vue project has three. The app runs in the browser, and vite.config.ts, Vite's settings file, runs in Node, which runs JavaScript on your computer. Each needs its own built-in types, such as document in the browser and process in Node.
The root one, tsconfig.json, only points at the other two:
{
"files": [],
"references": [
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.app.json" }
]
}
It checks nothing itself, and vue-tsc --build follows it to the other two. tsconfig.node.json covers vite.config.ts and the other tools' settings files, with Node's types from @tsconfig/node24, the base config it extends.
tsconfig.app.json covers your code. Here are its main lines:
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"compilerOptions": {
"noUncheckedIndexedAccess": true,
"paths": {
"@/*": ["./src/*"]
}
}
}
It covers src/ and env.d.ts, which adds Vite's own types, with the browser's types from the Vue team's base config.
paths makes an import that starts with @/ look in src/, from any folder.
Two settings decide how strict the check is. strict, on by default in TypeScript 6, makes you handle a value that may be missing (null or undefined) before you use it. noUncheckedIndexedAccess goes further: an item read from a list by its position may be undefined, because the list could be empty.
The greeting page prints a default size under its heading. In the Code tab, src/utils/sizes.ts holds a list of sizes and firstSize(), a function that returns the first one in lowercase:
export const sizes = ['S', 'M', 'L']
export function firstSize(): string {
// sizes[0] is string | undefined: the list could be empty
const first = sizes[0] ?? 'M'
return first.toLowerCase()
}
Written as const first = sizes[0], the next line fails the check with 'first' is possibly 'undefined'. The fallback fixes it: ?? gives the value on its right, 'M', when the one on its left is undefined. This list is not empty, so the page shows Default size: s.
TypeScript 6, not 7, and the editor
Two choices keep these checks working: the TypeScript version you install, and the extension in your editor.
TypeScript 7, rewritten in Go and about ten times faster, is now the latest version on npm. It ships without an API, the programming interface that vue-tsc and Vue - Official use to plug .vue files into TypeScript, so Vue projects stay on TypeScript 6.0 for now. create-vue pins "typescript": "~6.0.0", which accepts 6.0 patches and nothing newer.
In VS Code, install Vue - Official (id Vue.volar, once called Volar). create-vue's .vscode/extensions.json recommends it, so anyone who opens the folder is offered it.
What goes wrong
The first mistake drops the type check: a project that shortens build to plain vite build ships {{ user.nmae }}.
"build": "vite build"
The site deploys and every visitor reads "Hello" followed by nothing, because Vue renders undefined as an empty string. Keep the type check in build, and run npm run type-check as its own step in CI.
"build": "run-p type-check \"build-only {@}\" --"
The second mistake installs TypeScript 7: npm install -D typescript@latest writes this line.
"typescript": "^7.0.2"
The next npm run type-check crashes before it checks anything: Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './lib/tsc' is not defined by "exports". vue-tsc looks for a file that TypeScript 7 no longer has. Pin 6.0 and install again.
"typescript": "~6.0.0"
The third mistake copies baseUrl, the starting folder for paths, from an older project.
"baseUrl": ".",
"paths": { "@/*": ["./src/*"] }
The whole check fails on the config itself: Option 'baseUrl' is deprecated and will stop functioning in TypeScript 7.0. Specify compilerOption '"ignoreDeprecations": "6.0"' to silence this error. paths works without it, relative to the tsconfig file, so delete the line instead of silencing the error.
"paths": { "@/*": ["./src/*"] }
What to remember
- Vite strips types and never checks them.
vue-tsc --buildchecks the whole project, templates included, in thebuildscript and in CI. tsconfig.app.jsoncoverssrc/with browser types,tsconfig.node.jsoncoversvite.config.tswith Node types, and the roottsconfig.jsononly references them.- Handle the
undefinedthatnoUncheckedIndexedAccesspoints out, with a fallback such as?? 'M', instead of hiding it. - Stay on TypeScript 6 with
"typescript": "~6.0.0", because vue-tsc cannot run on 7, and leave outbaseUrl. In VS Code, Vue - Official checks as you type.
In your project
Do these in a real project. Each one says how to confirm it worked.- With Node 22 or 24, run
npm create vue@latest shop -- --ts, thencd shopandnpm install. Insrc/App.vue, addconst user = { name: 'Ada' }to the script and<h1>Hello {{ user.nmae }}</h1>to the template.npm run build-onlysucceeds, andnpm run type-checkprintsProperty 'nmae' does not exist on type '{ name: string; }'.Fix the typo and the check passes. - Copy
src/utils/sizes.tsfrom the Code tab into your project and change its fallback line toconst first = sizes[0].npm run type-checkreports'first' is possibly 'undefined'.Put?? 'M'back and the check passes. - Run
npx tsc -v. It printsVersion 6.0.3or a later 6.0 patch. If it prints 7, set"typescript": "~6.0.0"inpackage.jsonand runnpm install.