skip to content

SFC Checking Toolchain

Type-checking .vue files outside the editor: vue-tsc in CI, the official language server and editor extension, and why the bundler strips types without checking them. Interviewers probe the CI gap.

part ofVue.jsoverview, primer and where to startread it →
on this pageshow

explore

questions

5

In a Vite-based Vue 3 TypeScript project, why can the dev server and production build succeed despite type errors, and what catches them?

level: juniorimportance: must knowfreq 60%

answer

  1. transpile-only pipeline
  2. types stripped per file
  3. a separate checker
  4. editor plus CI script

basics

~20 s

Vue's Vite-based setup is transpilation-only: the dev server and bundler strip types from each file without type-checking, to stay fast. Type errors are caught by the editor's Vue language tools and by running vue-tsc --noEmit in a script or CI.

solid answer

~40 s

The Vue TypeScript guide states that with a Vite-based setup the dev server and bundler are transpilation-only and do not type-check. Each file's TypeScript is stripped in isolation, which keeps the dev server fast, but it means a wrong prop type or a typo in a template expression still builds and ships. Checking is a separate job: during development the official editor extension (Vue - Official) shows errors as you type, and on the command line `vue-tsc --noEmit`, a wrapper around `tsc` that understands `.vue` files, checks the whole project. Teams put `vue-tsc` in a `type-check` script and run it in CI, or before the build, so type errors fail the pipeline; it can also run in watch mode next to the dev server.

code

vue · 11 lines
vue
<script setup lang="ts">
import { ref } from 'vue'

const count = ref<number>(0)
</script>

<template>
  <!-- builds fine with a transpile-only pipeline; vue-tsc reports:
       Property 'toUppercase' does not exist on type 'number' -->
  <p>{{ count.toUppercase() }}</p>
</template>

go deeper

for a junior

Remember that the Vue Vite pipeline only strips types; type errors are reported by the editor extension and by vue-tsc, not by the build.

for a middle

Explain why transpile-only is per file and fast, and why the checker must see the whole program, including SFC templates, which only vue-tsc can do.

for a senior

Make type-checking a required CI step with vue-tsc, choose --noEmit or --build to match the tsconfig layout, and keep it off the dev server's critical path.

for a principal

Set the team's quality gate: which checks block a merge, where they run, and how fast they must be so developers do not route around them.

## What the build actually does with TypeScript In a Vue 3 project built with Vite, TypeScript in `.ts` files and in `<script lang="ts">` blocks is **transpiled**, not **type-checked**. The Vue TypeScript guide says so directly: with a Vite-based setup, the dev server and the bundler are transpilation-only and do not perform any type-checking. Transpiling means removing type annotations and turning the rest into JavaScript, **one file at a time**. A type checker instead needs the whole program: every import, every declaration, every component's props. The guide adds that the transpiler works under single-file limitations, which is why the scaffolded `tsconfig` enables `isolatedModules` (or the stricter `verbatimModuleSyntax`) so that code which a per-file transpiler cannot handle is flagged by the checker. The consequence: the following component builds and runs, and fails only at runtime or never visibly. ```vue <script setup lang="ts"> const props = defineProps<{ price: number }>() </script> <template> <span>{{ props.price.toFixd(2) }}</span> </template> ``` ## Why Vue chose this split - **Speed**: type-checking a whole project on every file change would slow the dev server down; stripping types per file is cheap. - **One source of truth**: errors should map back to the source you wrote. The guide criticises checking inside the webpack transform pipeline with `ts-loader`: it can only check post-transform code, which does not align with the errors shown by the IDE or `vue-tsc`. - **Separation**: the editor already runs a type checker in a separate process, so doing it again inside the bundler is a poor trade. ## What catches the errors | Where | Tool | When it runs | |---|---|---| | Editor | Vue - Official extension (Vue language server) | continuously while you type | | Terminal, dev time | `vue-tsc --noEmit --watch` | alongside the dev server | | Script or CI | `vue-tsc --noEmit` (or `vue-tsc --build` with project references) | before or alongside the build | `vue-tsc` is a wrapper around `tsc` that also understands `.vue` files, including the expressions in templates, so it reports errors plain `tsc` cannot see. ## Wiring it into the pipeline 1. Add a script such as `"type-check": "vue-tsc --noEmit"`. 2. Run it in CI as its own step, so a type error fails the pipeline even though `vite build` succeeds. 3. Optionally make the production build depend on it, for example by running both in the build script. 4. Keep it fast by checking the right tsconfig: with project references, point it at the app config or use `--build`. ```json { "scripts": { "type-check": "vue-tsc --noEmit", "build": "vue-tsc --noEmit && vite build" } } ``` ## What each layer can and cannot catch | Layer | Catches | Misses | |---|---|---| | Transpile step (dev server, build) | syntax errors, invalid SFC structure, template compile errors | every type error | | Editor extension | type errors in open files, including templates | files nobody opens; teammates without the extension | | `vue-tsc` in CI | type errors across every file the tsconfig includes | files outside that tsconfig's `include` | The middle row explains why the editor alone is not a gate: it reports what a developer looks at, not the whole project. The last row explains why the CI command must point at the right configuration. ## Common misconceptions - **"`lang=\"ts\"` makes the build strict."** It only tells the transpiler and the language tools that the block is TypeScript. - **"The dev server's error overlay shows type errors."** It shows syntax and compile errors from transpiling, not type errors. - **"`tsc --noEmit` is enough."** Plain `tsc` does not understand `.vue` files, so it cannot check SFCs or their templates. - **"Editor errors will stop a bad commit."** Only if something in CI or a hook runs `vue-tsc`; the editor cannot block a merge.

  • Why does the Vue TypeScript guide advise against type-checking inside the webpack build with ts-loader?
    Checking needs the whole module graph, while a loader sees one transformed module at a time. The guide lists three problems: `ts-loader` only checks post-transform code, so errors do not line up with the IDE or `vue-tsc`; checking in the same process slows the whole build; and the IDE already type-checks in a separate process.
  • How can a Vue developer see type errors from the terminal during development without slowing the dev server?
    Run `vue-tsc --noEmit --watch` in a second terminal, or in parallel with the dev server from one script. It re-checks on file changes in its own process, so the dev server stays transpile-only and fast, and the editor extension still gives instant feedback per file.

The bundler is a printing press: it prints whatever manuscript it is given, quickly, without proofreading. vue-tsc is the proofreader, and a book only gets proofread if someone puts that step in the workflow.

saying these in an interview costs you the question

  • Vite type-checks .vue files during vite build, so a green build means no type errors.
  • Adding lang="ts" to the script block makes the dev server reject type errors.
  • Plain tsc --noEmit also checks templates in single-file components.
  • The dev server's error overlay reports TypeScript type errors.
  • Editor squiggles are enough to keep type errors out of main.
open as a page

Which editor tooling does Vue 3 officially provide for TypeScript in single-file components, and how does it relate to vue-tsc?

level: juniorimportance: should knowfreq 40%

basics

~20 s

The official Vue - Official extension (previously Volar) bundles the Vue language server and a TypeScript plugin that lets the editor's TypeScript service understand .vue files. It shares its core with vue-tsc, so editor and CLI checks normally agree.

open as a page

What is vue-tsc, and why can't plain tsc type-check Vue single-file components and their templates?

level: middleimportance: should knowfreq 45%

basics

~20 s

Plain tsc only understands TypeScript and JavaScript files, not .vue. vue-tsc wraps tsc with Vue's language plugin, which turns each SFC, template expressions included, into virtual TypeScript that tsc checks, and it accepts tsc's usual flags.

open as a page

In a Vue 3 project, the CI type-check step passes but the editor shows type errors in a component's template. What would you investigate?

level: seniorimportance: should knowfreq 35%

basics

~20 s

Check whether CI really runs vue-tsc (not tsc or just the build), whether its tsconfig includes the .vue file, whether a references-only root config checks nothing, and whether TypeScript, tool versions or vueCompilerOptions differ from the editor's.

open as a page

In Vue's language tooling, what does the vueCompilerOptions setting strictTemplates change, and what is checked in templates without it?

level: middleimportance: nice to knowfreq 20%

basics

~20 s

strictTemplates is a vueCompilerOptions flag in tsconfig.json, off by default. Turning it on enables strictVModel and the checkUnknownProps, Events, Components and Directives checks, so unknown names in templates become errors in vue-tsc and the editor.

open as a page