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?
answer
- is CI really running vue-tsc
- which tsconfig, which files
- solution-style root config
- versions and vueCompilerOptions
basics
~20 sCheck 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.
solid answer
~40 sFirst confirm what CI runs: a `vite build` or plain `tsc` never checks templates, so only `vue-tsc` counts. Then confirm what it checks: `vue-tsc --noEmit` on a solution-style root `tsconfig.json` with `"files": []` and `references` checks nothing, because references are only followed with `--build`; use `vue-tsc --build` or `-p tsconfig.app.json`. Check that the config's `include` actually matches `src/**/*.vue`. Next compare settings: the editor applies the `vueCompilerOptions` of the tsconfig that includes the file, so `strictTemplates` or a `checkUnknown*` option set there but not in CI's config produces editor-only errors. Finally compare versions: the editor may use its bundled TypeScript and a newer extension, while CI runs the lockfile's `typescript` and `vue-tsc`. Reproduce with `npx vue-tsc --noEmit -p` on the editor's config, then align CI with it.
code
vue · 9 lines<script setup lang="ts">
import UserBadge from './UserBadge.vue' // declares props { name: string }
</script>
<template>
<!-- red in the editor when tsconfig.app.json sets strictTemplates;
CI stays green if it runs vue-tsc --noEmit on a references-only root -->
<UserBadge name="Ada" :size="'large'" />
</template>go deeper
Remember that only vue-tsc checks templates; a green build or a plain tsc run proves nothing about them.
Explain how the tsconfig choice changes what is checked, especially the references-only root config and include patterns that miss .vue files.
Reproduce the editor's check on the command line, align TypeScript and vue-tsc versions and vueCompilerOptions, and make CI fail before fixing the component.
Standardise one type-check entry point for editors, hooks and CI, so configuration and version drift cannot silently lower the quality gate.
## Why this happens at all The Vue - Official editor extension and `vue-tsc` share `@vue/language-core`, so on the same file, with the same configuration and versions, they report the same errors. When CI is green and the editor is red, one of those three inputs differs, or CI is not checking the file at all. ## 1. Is CI actually type-checking SFCs? - **Only a build step.** `vite build` is transpile-only; the Vue guide says the bundler performs no type-checking. - **Plain `tsc`.** `tsc --noEmit` does not understand `.vue` files, so templates are never checked. A `declare module '*.vue'` shim makes imports compile and hides the rest. - **An ignored exit code.** A script like `vue-tsc --noEmit || true`, or a step marked as allowed to fail. ## 2. Which tsconfig does it check? The Vue guide notes that projects scaffolded with `create-vue` use **project references**, so app code and test code get different global types. The usual shape is a solution-style root `tsconfig.json` that includes no files itself and points at separate configs: ```jsonc // tsconfig.json (root, solution-style) { "files": [], "references": [ { "path": "./tsconfig.node.json" }, { "path": "./tsconfig.app.json" } ] } ``` Running `vue-tsc --noEmit` against that root file checks **nothing**: it has no files of its own, and references are only built in build mode. The fixes: 1. Use `vue-tsc --build`, which checks every referenced project. 2. Or point at the app config explicitly: `vue-tsc --noEmit -p tsconfig.app.json`. 3. Confirm the app config's `include` covers the components, for example `src/**/*` and `src/**/*.vue`. The editor, by contrast, uses the config that actually includes the open file, typically `tsconfig.app.json`, so it sees errors CI never looked for. ## 3. Are the Vue checking options the same? Both tools read **`vueCompilerOptions`** from the tsconfig that owns the file. If `tsconfig.app.json` enables `strictTemplates` or options like `checkUnknownProps`, while CI checks through a different config without them, unknown props, events or components are errors in the editor only. ## 4. Are the versions the same? | Input | Editor | CI | |---|---|---| | TypeScript | bundled with the editor unless `typescript.tsdk` points at the workspace | the project's installed `typescript` | | Vue language tooling | the extension's version, auto-updated | `vue-tsc` pinned by the lockfile | | Config | the tsconfig that includes the open file | whatever the CI command selects | The extension README recommends the workspace TypeScript version for exactly this reason. A newer extension can also infer templates more precisely than an older `vue-tsc`; upgrade `vue-tsc` so CI catches what the editor catches. ## A reproduction routine 1. Run the CI command locally and confirm it passes. 2. Run `npx vue-tsc --noEmit -p tsconfig.app.json`, the extension's own troubleshooting check aimed at the editor's config. 3. If step 2 fails, fix the CI command or config; if it passes, compare TypeScript and tool versions. 4. Make CI fail on the reproduced error before fixing the component, so the gap cannot reopen. ## Symptoms mapped to causes | Symptom | Likely cause | |---|---| | CI passes instantly, even on a large project | the checked config contains no files, or the step only builds | | CI passes, editor flags unknown props or components | `vueCompilerOptions` differ between the configs each tool uses | | CI passes, editor flags an inference error after an extension update | newer language tooling than the pinned `vue-tsc` | | Errors differ between two developers' editors | one uses the bundled TypeScript, the other the workspace version | | CI fails on files nobody has open | CI is right: the editor only reports files you open | A suspiciously fast type-check is itself a signal: checking a real Vue project takes noticeable time, so a near-instant green run usually means an empty program. ## Preventing it - One `type-check` script used by developers and CI alike. - `vue-tsc --build` whenever the project uses references. - The workspace TypeScript version committed in the editor settings. - `vue-tsc` and `typescript` upgraded together.
- Why does `vue-tsc --noEmit` on a Vue project's references-only root tsconfig report no errors at all?The root config lists `"files": []` and only references other configs. Outside build mode, references are not checked as projects of their own, so the program is empty and there is nothing to report. Use `vue-tsc --build` to check every referenced project, or pass the app config with `-p`.
- The editor flags an unknown prop on a Vue component, but vue-tsc run on the same config passes. What differs?Probably the versions. Check which TypeScript the editor uses; the Vue - Official README recommends the workspace version via `typescript.tsdk`. Then compare the extension's version with the `vue-tsc` version in the lockfile, since newer language tooling can infer templates differently. Align both, and upgrade `vue-tsc` if the editor is right.
saying these in an interview costs you the question
- If vite build passes in CI, the templates must be type-correct.
- vue-tsc --noEmit on the root tsconfig checks every referenced project.
- The editor is just stricter by nature, so its errors can be ignored.
- vueCompilerOptions are editor settings and never affect vue-tsc.
- The editor and CI always use the same TypeScript version automatically.