新闻详情

新闻详情

首页 / 资讯中心 / 详情

Vue项目tsconfig/jsconfig与compilerOptions避坑

发布时间:2026/10/1 14:02:52来源:尧图网络
Vue项目tsconfig/jsconfig与compilerOptions避坑
前阵子帮朋友捞一个 Vue 项目的编辑器报错症状挺有意思VS Code 里满屏红波浪线/components/xxx一律“找不到模块”可命令行一跑vite dev页面照常渲染一点问题没有。翻了下他的工程目录根下同时躺着jsconfig.json和tsconfig.json两个文件内容还各写了一半一个配了paths没配include另一个配了include却写错了moduleResolution。把这两个文件理清楚之后红波浪线瞬间消失。这件事让我意识到jsconfig.json、tsconfig.json以及里面的compilerOptions是 Vue 项目里最容易被“复制粘贴”蒙混过去的一块配置——大家都能跑起来但很少有人能说清楚哪一行配置到底在管谁。这篇东西面向的读者很宽刚学 Vue、第一次自己搭工程的新手能从里面拿到可直接抄的配置模板已经写过一两个项目、被类型报错折腾过的中级开发者能搞懂compilerOptions每个开关背后的取舍做前端基建、要给团队定规范的也能参考后面多环境分层的那套做法。核心就一件事把 Vue 项目里这两个 JSON 文件讲透顺便把compilerOptions里真正影响开发体验的字段一个个拆开告诉你它为什么这么写、不这么写会出什么事。1. 先分清 jsconfig.json 和 tsconfig.json 到底谁在管谁1.1 两个文件的血缘关系一个简化版一个完整版很多人以为这是两套完全独立的机制其实不是。jsconfig.json可以理解成tsconfig.json的“降级亲戚”——它本质上是被同一套语言服务解析的格式、字段名、层级结构基本一致只是它面向纯 JavaScript 项目不涉及类型检查器的完整能力。在没有 TypeScript 编译器的纯 JS 工程里编辑器需要一个信号来判断“这个目录是一个项目根”jsconfig.json就是那个信号同时它还能顺便承担路径别名、include/exclude范围、checkJs之类的语言服务配置。而tsconfig.json是 TypeScript 编译器的正式配置文件它管的不只是编辑器里的智能提示还包括tsc、vue-tsc这类命令行工具的类型检查行为、模块解析策略、输出目标等。Vue 3 项目里如果用了script setup langts那tsconfig.json就是必需品如果整个项目还是纯 JS只用到script setup其实jsconfig.json就够了。关键点是jsconfig.json支持的字段是tsconfig.json的子集。像noEmit、composite、declaration这种和产物输出强相关的字段放在jsconfig.json里没有意义因为 JS 项目根本不走 TS 的编译输出流程。反过来你在jsconfig.json里写的paths、baseUrl、include换成tsconfig.json一样能用甚至写法都一模一样。提示如果你打算把项目从 JS 迁到 TS不必新建一个文件重头写。直接把jsconfig.json改名成tsconfig.json再补上strict、noEmit这类字段就行编辑器认得出来。1.2 同一目录下两个文件同时存在会发生什么这是最容易被忽略的坑。当项目根目录下同时存在jsconfig.json和tsconfig.json时编辑器的语言服务会优先采用tsconfig.jsonjsconfig.json就成了一个死文件你改它里面的paths也不会有任何反应。我见过好几个项目是这样早期是 JS 项目写了jsconfig.json后来迁到 TS新建了tsconfig.json但旧的jsconfig.json忘了删。结果开发者一直在改旧文件一边改一边骂编辑器不生效。所以我的第一条硬性建议是一个项目根目录里这两个文件只留一个。纯 JS 项目留jsconfig.json沾了 TypeScript 就留tsconfig.json不要共存不要指望它们会合并。清理旧文件这件事花不了十秒钟但能省掉半天排查。1.3 真正读你配置的三方语言服务、类型检查器、构建工具搞清楚“谁在读配置”后面所有问题都会顺很多。Vue 项目里至少有三个角色在跟这份 JSON 打交道但它们读的东西完全不一样。第一个是编辑器的语言服务。在 Vue 3 生态里这一角色由 Vue Language Features也就是大家常说的 Volar加上 TypeScript 语言服务共同承担。它负责给你补全、跳转定义、显示类型、标红波浪线。它读的是项目根目录的tsconfig.json或jsconfig.jsonpaths别名能不能跳转全靠它。第二个是类型检查器通常是vue-tsc。它是你跑npm run type-check或 CI 里那道检查时真正干活的东西。它只认tsconfig.json只认这个文件里声明的include范围与compilerOptions规则跟编辑器那套提示是两条独立的链路。第三个是构建工具Vite 或 webpack。这里最反直觉Vite 默认不做任何类型检查它用 esbuild 做单文件转译速度极快但代价是它基本不看你的compilerOptions。你在tsconfig.json里配的paths别名Vite 是不认的——它只认vite.config.ts里的resolve.alias。这就解释了为什么会出现“编辑器不报错但跑起来 404”和“编辑器报错但能跑”这两种看似矛盾的现象。理解了这三方分工后面遇到任何配置问题你第一反应就应该是这个现象是编辑器报的还是命令行报的如果是编辑器报的去查tsconfig.json的include和paths如果是构建报的去查 Vite 配置。2. compilerOptions 逐项拆解哪些字段真的在影响你2.1 target、lib、module 与 moduleResolution 的选型逻辑target决定 TS 编译时按哪个 ECMAScript 版本做语法降级。理论上你可以写ES5让老浏览器也能跑但在 Vue 3 Vite 的场景下这基本是自我折磨。Vite 的生产构建走 Rollup现代浏览器的兼容由build.target单独控制TS 这一层的target只影响类型检查和少量语法转换。所以我的做法是统一写ESNext让 TS 不要把语法降级兼容交给构建侧统一决策。lib决定你有哪些全局类型可用。写[ESNext, DOM, DOM.Iterable]是标配DOM.Iterable特别重要因为它让NodeList、FormData这些类型支持迭代器不然你在for...of遍历document.querySelectorAll的结果时会莫名其妙报错。如果项目要跑在 Node 脚本里那还要加[node]到types里注意types和lib是两件事前者管types/*包的引入后者管内置类型库。module和moduleResolution是搭档必须成对考虑。Vue 3 Vite 项目里我强烈建议module: ESNext配moduleResolution: Bundler。Bundler模式模拟的是打包器的解析行为允许你写不带扩展名的导入、支持package.json里的exports字段、也允许import时省略index.ts。它比老牌的Node模式更贴合实际运行环境Vite、esbuild、Rollup 全都按这套逻辑干活。有个约束要注意moduleResolution: Bundler只能和module: ESNext或module: Preserve搭配写成CommonJS会直接报配置错误。2.2 paths 与 baseUrl为什么你的 别名编辑器不认先说结论paths是纯类型层面的路径映射它不改变运行时行为一分钱都不改变。它的唯一作用是让语言服务和vue-tsc在解析模块时把/utils/foo翻译成真实路径去找类型。真正的运行时解析是 Vite 的resolve.alias干的活。在早期 TS 版本里paths必须配合baseUrl才能用所以你会看到大量老模板写成这样{ compilerOptions: { baseUrl: ., paths: { /*: [src/*] } } }baseUrl的意思是“所有非相对路径导入都从这里开始找”。但 TS 4.1 之后paths可以独立使用了路径相对于tsconfig.json自身所在目录解析。所以现在官方模板更推荐这么写{ compilerOptions: { paths: { /*: [./src/*] } } }两种写法都能用但要注意一个细节一旦你写了baseUrl所有非相对导入的基准目录就变了某些第三方类型的解析路径会跟着偏移偶尔能引发很诡异的“找不到类型定义”。没历史包袱的项目我建议直接省掉baseUrl只写paths。至于别名匹配规则是“最长前缀优先”/a/*会优先于/*所以你可以定义多个层级不用担心互相打架。两边配置必须一致这是最容易踩的坑。tsconfig.json里写了/*vite.config.ts里没写结果就是编辑器一切正常一刷新页面 500反过来 Vite 里写了而 TS 里没写跑起来没问题但编辑器满屏红。所以我在团队里的规定是加别名就两个文件一起改写完立刻跑一次type-check加一次构建验证。2.3 strict 家族要不要一步到位strict: true是一个总开关它一次性打开noImplicitAny、strictNullChecks、strictFunctionTypes、strictBindCallApply、strictPropertyInitialization、noImplicitThis、alwaysStrict等一堆子开关。新项目没得说直接开。但如果你接手的是一个存量的 JS 项目要迁移一步到位打开strict通常会蹦出上千个错误开发直接停摆。比较务实的做法是分层开。第一步只开noImplicitAny: false但打开strictNullChecks: true因为空值问题才是线上崩溃的头号来源。等业务代码消化得差不多了再把noImplicitAny打开逼着大家写类型。最后再补strictPropertyInitialization这个开关会要求 class 的每个非可选属性在构造函数里初始化对接一些老代码时挺烦但对于用了defineComponent加setup的 Vue 3 组件影响其实不大。还有几个“独立于 strict 之外”的检查项值得单独说。noUnusedLocals和noUnusedParameters会报未使用的变量和参数提前开它能把脏代码扼杀在编辑器里但代价是调试时临时注释掉一行代码就报错有点烦。noFallthroughCasesInSwitch我建议一定开switch 忘了break是真会出线上事故的。noImplicitReturns也挺值强制函数在所有分支上都有返回值避免出现某个分支默默返回undefined。2.4 和打包语义强相关的几个开关isolatedModules: true这个开关在 Vue 3 Vite 项目里是必须开的。原因是 esbuild 和 Babel 都是单文件转译它们不知道其他文件的内容只能按语法独立处理每个文件。这时候如果你写了export { SomeType }这种“导出类型但看起来像导出值”的写法单文件转译器没法判断运行时就会报错。打开这个开关后TS 会强制你写export type { SomeType }把意图明确出来。verbatimModuleSyntax: true是 TS 5.0 引入的新开关它是importsNotUsedAsValues和preserveValueImports的替代方案后者现在已废弃。打开它之后你必须显式用import type来导入纯类型否则 TS 会报错。这个规则看着严苛但收益很大它让“类型导入”和“值导入”清清楚楚构建产物体积也更可控还能避免循环依赖引发的运行时诡异问题。我自己的新项目一律开。skipLibCheck: true这个几乎是人人都开但很少有人知道原因的开关。它跳过对node_modules里.d.ts文件的类型检查。不开的话你项目里任何一处第三方类型的版本不兼容都会在tsc时炸出来而这些错你还改不了。开了之后检查速度会明显变快尤其是装了几十个依赖的项目能从几十秒降到几秒。esModuleInterop: true配合allowSyntheticDefaultImports解决的是 CommonJS 和 ESM 混用时的默认导入问题。比如import path from path在esModuleInterop关闭时会报错因为path模块没有默认导出。打开之后就顺了。Vue 项目里如果引用了 Node 生态的老库这两个开关基本是刚需。useDefineForClassFields这个开关由target隐式决定。target在ES2022及以上时默认为true此时 class 字段用的是标准语义defineProperty而不是构造期赋值。绝大多数 Vue 3 项目用不上 class 组件所以这个开关基本感知不到但如果你引入了基于装饰器的库就得留意它的值。resolveJsonModule: true允许你直接import data from ./data.jsonTS 会自动推断出 JSON 结构的字面量类型。Vue 项目里用来加载一些静态配置表很方便。注意它要求moduleResolution不是classic现代配置都没问题。noEmit: true在 Vite 项目里基本是标配。因为类型检查和产物输出是分离的产物由 Vite 出TS 只负责查类型不负责写文件。不开这个tsc会真的往磁盘写.js跟 Vite 的输出互相覆盖排查起来很折磨人。moduleDetection: force是个小但实用的开关。默认情况下TS 判断一个文件是不是模块看它有没有import/export。没有的话就当成全局脚本处理于是两个文件里定义的同名变量可能冲突。设成force之后所有文件都被视为模块这类玄学报错基本消失。2.5 vueCompilerOptionsVolar 专属的那块配置这一块不在compilerOptions里而是和它平级的顶层字段专门给 Vue 语言服务用。很多人不知道它的存在但它对 Vue 项目的开发体验影响巨大。{ vueCompilerOptions: { target: 3.5, strictTemplates: true, plugins: [] } }target声明你的 Vue 版本Volar 会据此决定模板的解析规则。写3.5、3.4这样的细分版本号比笼统写3更准确尤其是在用defineModel、defineSlots这类随版本演进的新宏时写错版本会出现“宏不认识”的报错。strictTemplates是这块配置里价值最高的开关。打开后模板里的事件参数、props传参、v-for的迭代类型都会被严格检查。比如父组件给子组件传了个少一个字段的对象或者事件回调参数类型写错都能在编辑器里直接标出来不用等运行时。代价是初期会有不少报错尤其是用了一些动态组件、v-bindprops的写法。我的建议是新项目直接开老项目可以等业务稳定了分批开。plugins用来挂 Volar 插件比如配合宏扩展方案时需要在编辑器侧注册。这块和构建侧的插件是两码事两边都要配漏一边就会出现“构建成功了但编辑器报错”的情况。另外Volar 现在推荐启用 Take Over Mode接管模式也就是关掉其他提供 Vue 支持的老插件避免两个语言服务打架。这类冲突的表现通常是类型提示时有时无跳转莫名其妙跳到错误位置重启编辑器能好一会儿然后继续出问题。3. 手把手落地从纯 JS 到 TS 的配置演进3.1 纯 JS Vite 项目的最小可用 jsconfig.json假设你手上是一个 Vite 创建的纯 JS 项目用了别名想让编辑器别乱报错。jsconfig.json写这么多就够了{ compilerOptions: { target: ESNext, module: ESNext, moduleResolution: Bundler, paths: { /*: [./src/*] }, allowJs: true, checkJs: false, jsx: preserve, resolveJsonModule: true, isolatedModules: true, skipLibCheck: true, types: [vite/client] }, include: [src/**/*.js, src/**/*.vue], exclude: [node_modules, dist] }逐个说下为什么要这么写。allowJs必须开不然.js文件根本不在语言服务的管辖范围。checkJs我建议先关因为一开就会在 JS 文件上做类型推断检查存量代码会瞬间爆红想逐步加强的话可以在单个文件顶部加// ts-check注释只让那一份文件参与检查这个做法在渐进迁移时特别好用。types: [vite/client]是为了让import.meta.env这类 Vite 注入的全局变量有类型不写的话编辑器会提示import.meta.env未定义或者给出的类型是any。include里显式写上.vue是为了确保单文件组件被纳入项目范围不加的话某些跨文件类型推导会失效。一个实操细节改完jsconfig.json后编辑器不一定立刻生效。比较稳的做法是CtrlShiftP执行重启 TS 服务的命令或者干脆重启 VS Code 窗口。还有一种情况语言服务会缓存上次解析的结果配置文件写错了它不报错只是默默不生效这时候可以通过命令面板里的“打开 TS 项目配置”来确认编辑器当前到底读的是哪个文件、解析出来的最终配置是什么。这个功能排查配置问题非常有用比反复猜要快得多。3.2 引入 vue-tsc 后的 tsconfig.json 完整版项目一旦开始写 TS就换成tsconfig.json。现代 Vue 3 模板通常采用“根文件 两个子配置”的结构根文件只做引用不写实际规则{ files: [], references: [ { path: ./tsconfig.app.json }, { path: ./tsconfig.node.json } ] }这种写法的好处是职责分离。应用代码和构建脚本的编译环境完全不同前者跑在浏览器里需要DOM类型后者跑在 Node 里需要types/node还要允许导入fs、path。混在一个tsconfig.json里要么给应用代码塞进 Node 类型污染全局要么构建脚本拿不到 Node 类型。应用侧的tsconfig.app.json大致长这样{ extends: vue/tsconfig/tsconfig.dom.json, include: [env.d.ts, src/**/*, src/**/*.vue], exclude: [src/**/__tests__/*], compilerOptions: { composite: true, tsBuildInfoFile: ./node_modules/.tmp/tsconfig.app.tsbuildinfo, paths: { /*: [./src/*] } } }extends指向官方的 Vue TS 基础配置里面已经预设好了target、lib、module、moduleResolution、strict、isolatedModules、skipLibCheck这一整套推荐值你不用重复写。composite: true是配合项目引用要求的它会让 TS 生成增量编译信息加快第二次检查的速度。tsBuildInfoFile把这些中间产物丢到node_modules/.tmp下避免污染项目根目录。构建脚本侧的tsconfig.node.json{ extends: tsconfig/node20/tsconfig.json, include: [vite.config.*, vitest.config.*, cypress.config.*], compilerOptions: { composite: true, noEmit: true, module: ESNext, moduleResolution: Bundler, types: [node] } }这里types: [node]是关键它让path、process、__dirname这些在vite.config.ts里能正常使用。include只圈定配置文件本身不要写成src/**/*否则应用代码会被 Node 环境规则检查一遍容易出现莫名其妙的报错。注意composite: true和noEmit: true在部分 TS 版本下会冲突。如果你的vue-tsc报“复合项目不能禁用输出”之类的错把noEmit换成emitDeclarationOnly加一个outDir指到临时目录里就能绕过去。3.3 从 JS 逐步迁移到 TS 的四步走法迁移这事最忌讳“大爆炸”。我自己的做法分四步每一步都可独立回滚。第一步保留jsconfig.json先只加include和paths把编辑器的别名跳转打通。这一步不改任何业务代码风险为零。第二步把jsconfig.json改名为tsconfig.json加上allowJs: true、checkJs: false、strict: false。此时项目里一个.ts文件都没有但类型系统已经就位。这个状态可以保持很久团队没有任何感知。第三步从工具函数、常量、类型定义这些“叶子模块”开始改成.ts。这些模块依赖少、逻辑独立改起来的收益也最快。同时把strictNullChecks打开让新写的代码先享受严格检查。第四步逐步收紧。把noImplicitAny打开让any显式化等any消化得差不多再打开整体strict。这个过程可能持续几个月不用急重要的是每次收紧都在 CI 里跑通别让报错堆积成山。有个小技巧迁移期间可以在tsconfig.json里用include的差异做“白名单”控制。先把要检查的目录列进去其他目录暂时排除等改完一批再往里加。这样错误总数始终是可控的不至于每天打开编辑器就是一片红。3.4 多环境分层别把所有规则塞进一个文件除了应用和构建脚本稍微成规模的项目还会有测试、服务端渲染、Electron 主进程等不同运行环境。这时候可以考虑按环境拆更多子配置比如tsconfig.vitest.json专门给测试文件用加上types: [vitest/globals]让describe、it、expect这些全局函数有类型。分层配置有一个容易忽略的坑extends是单向覆盖的子配置里写的compilerOptions会整体替换父配置里的同名键而不是做深合并。比如父配置里lib是[ESNext, DOM]子配置里写lib: [ESNext]结果就是DOM类型全没了所有document相关的代码全报错。所以子配置里如果要动lib、types这类数组字段记得把父配置里需要的项也一起写全。另外TS 5.0 之后extends支持数组写法可以一次继承多个基础配置后面的覆盖前面的。这个特性在多框架混用的仓库里挺有用不用再写一个中间文件做拼接。4. 常见报错与排查技巧实录4.1 典型报错速查表报错现象大概率原因排查动作找不到模块/xxx或提示缺少类型声明tsconfig的paths缺失或 Vite 的resolve.alias缺失两边一起查用“打开 TS 项目配置”确认编辑器读的是哪份配置.vue文件无法被导入include里没写src/**/*.vue或语言服务未启用检查include确认 Vue 语言服务插件已启用且没有冲突插件import.meta.env类型为any或报未定义types里没加vite/client或缺少env.d.ts补上类型声明文件与types字段检查通过但构建报模块解析错误moduleResolution与实际打包器不匹配改成Bundler并检查module是否兼容报“无法在模块外部使用 import 语句”文件被判定为脚本而非模块加moduleDetection: forcetsc输出文件把 Vite 产物覆盖了没开noEmit打开noEmit把类型检查与产物输出解耦事件回调参数在模板里类型是any没开strictTemplates在vueCompilerOptions里打开升级 TS 后一堆第三方类型报错skipLibCheck未开打开skipLibCheck4.2 “找不到模块 /xxx”的三层排查法这个报错我处理过太多次了已经形成了固定套路。第一层查tsconfig确认paths里的通配符写法和实际导入路径能对上。注意一个细节/*: [./src/*]里的./不能省省了之后解析基准会变成baseUrl如果你同时写了baseUrl路径就会跑偏一层导入/utils/a实际会去找src/src/utils/a。第二层查 Vite 配置resolve.alias里必须有对应的指向path.resolve(__dirname, src)。Vite 的别名是字符串前缀匹配和/效果不一样写会把所有以开头的包名也吃掉所以要么写成/要么用正则精确匹配。这个坑很容易被忽略直到你装了一个名字以开头的组织包才发现。第三层查语言服务是否真的在干活命令面板执行“选择 TypeScript 版本”确认用的是工作区里安装的版本而不是编辑器内置的老版本。编辑器内置版本通常比项目里装的旧某些新的解析规则它不认识就会出现“命令行能过、编辑器报错”的分裂现象。统一用工作区版本能消除这类差异也保证了团队成员之间的一致性。4.3 编辑器与命令行结论不一致怎么办这种“分裂”现象有四个常见成因按发生频率排序。最常见的是编辑器用了内置 TS 版本解决方式就是上面说的切到工作区版本。第二常见的是语言服务换过插件旧的 Vue 支持插件和新插件同时启用两个服务各说各话表现是提示时好时坏。这时候要统一到一套插件上并开启接管模式。第三个原因是配置没有被重新加载。修改tsconfig.json之后语言服务需要重新解析但这个重载不是总那么及时。手动重启 TS 服务或者重开窗口能解决大部分“改了没反应”的疑惑。第四个原因是项目引用没有被正确识别。用了根配置加子配置的结构后如果子配置里的composite没开或者根配置的references路径写错语言服务就找不到对应子项目回退到默认配置表现就是“编辑器读不到任何自定义规则”。排查办法是在命令面板里查一下当前文件属于哪个项目找不到的话就是引用链断了。4.4 几个不常见但很折磨人的坑有个坑是大小写敏感。macOS 和 Windows 的文件系统默认不区分大小写Linux 区分。本地开发时import Foo from ./foo和实际文件Foo.vue混用本地一点问题没有一上 CI 就全挂。开启forceConsistentCasingInFileNames在新版配置里已默认开启能在写代码阶段就拦住这类错误。这个开关建议永远保持开启尤其是在多人协作的项目里。还有个坑是类型导入被当成值导入。表现为构建产物里多出一堆本该被擦除的代码或者在打包时提示某个只包含类型的模块不存在。根源就是没开verbatimModuleSyntax或者没写import type。开了这个开关之后TS 会强制你把类型和值分清楚虽然写起来多打几个字但能避免很多构建期的诡异问题。最后一个坑是装饰器与新 class 字段语义的冲突。用了一些基于装饰器的库同时target设得很高就会触发useDefineForClassFields的标准语义导致装饰器行为和预期不符。解决办法要么调低target并显式关掉这个开关要么升级到支持标准装饰器的库版本。这类问题排查起来很耗时因为报错信息通常和实际原因离得很远。5. compilerOptions 与构建工具的边界在哪5.1 Vite 到底读了 tsconfig 里的哪些字段这是个值得记住的清单。Vite 用 esbuild 做开发期转译esbuild 会读取tsconfig.json中的少数几个字段target、jsx、jsxFactory、jsxFragmentFactory、useDefineForClassFields、experimentalDecorators、emitDecoratorMetadata、verbatimModuleSyntax这几项会影响它的转译行为。除此之外的字段esbuild 一概不看。也就是说strict、noUnusedLocals、strictNullChecks这些纯检查类的开关Vite 完全无视——你写多少都没用构建照样成功。这就是“为什么代码里有一堆类型错误项目还能跑起来”的根本原因。类型错误只会在vue-tsc跑的时候或者编辑器里出现构建流程根本不在这个链路上。paths更是个典型。Vite 完全不读它所以你必须额外配resolve.alias。如果你实在不想维护两份别名配置可以引入vite-tsconfig-paths之类的插件让 Vite 去读tsconfig.json的paths。这个方案在中小项目里挺好用能消除两处不一致的风险但大型项目里我倾向于手动配因为显式声明更可控排查问题时一眼就能看到映射关系。5.2 需要双份配置的几个要点除了paths还有两个地方容易出现“编辑器一套、构建一套”的情况。一是target。tsconfig里的target影响类型检查和 esbuild 的语法降级范围但真正决定生产产物的兼容目标是vite.config.ts里的build.target。如果你需要支持比较老的浏览器两个地方都要调低只调一处就会出现“本地测好、线上白屏”的情况。二是jsx。如果你在项目里用了tsx写组件tsconfig里通常写jsx: preserve意思是保留 JSX 语法交给构建器处理。但 Vite 侧的 esbuild 也需要知道怎么转换虽然它会读tsconfig的jsx字段但如果你在vite.config.ts里覆盖了相关配置两边就可能不一致。建议这类项目在两个文件里把 JSX 相关的注释写清楚避免后来接手的人搞混。5.3 三份可直接复制的配置模板第一份纯 JS 项目的jsconfig.json{ compilerOptions: { target: ESNext, module: ESNext, moduleResolution: Bundler, paths: { /*: [./src/*] }, allowJs: true, checkJs: false, isolatedModules: true, skipLibCheck: true, resolveJsonModule: true, moduleDetection: force, types: [vite/client] }, include: [src/**/*.js, src/**/*.vue], exclude: [node_modules, dist] }第二份Vue 3 TS 项目的tsconfig.app.json{ extends: vue/tsconfig/tsconfig.dom.json, include: [env.d.ts, src/**/*, src/**/*.vue], compilerOptions: { composite: true, tsBuildInfoFile: ./node_modules/.tmp/tsconfig.app.tsbuildinfo, paths: { /*: [./src/*] }, strict: true, noUnusedLocals: true, noFallthroughCasesInSwitch: true, verbatimModuleSyntax: true, moduleDetection: force }, vueCompilerOptions: { target: 3.5, strictTemplates: true } }第三份工具脚本用的tsconfig.node.json{ extends: tsconfig/node20/tsconfig.json, include: [vite.config.*, vitest.config.*, scripts/**/*], compilerOptions: { composite: true, noEmit: true, module: ESNext, moduleResolution: Bundler, types: [node] } }这三份覆盖了绝大多数 Vue 项目的场景。抄的时候注意按项目实际情况调整include路径env.d.ts如果你的类型声明文件叫别的名字也要跟着改。6. 几条我从实际项目里踩出来的固定习惯关于include的写法我现在的习惯是尽量精确不要图省事写**/*。原因很实际把node_modules、dist、测试产物全圈进来之后类型检查耗时能翻好几倍而且偶尔会因为某些依赖自带的声明文件有瑕疵而报一堆莫名其妙的错。精确圈定src、类型声明文件、必要的配置文件是性价比最高的一种优化。项目变大之后这一条能省下来的时间是以分钟计的。关于版本管理有一条经验值得强调TypeScript 和vue-tsc的版本要锁定。这两个东西对类型解析的行为差异相当大团队里如果 A 同学装的是 TS 5.4B 同学装的是 5.7同一个文件很可能呈现不同的报错结果然后大家就开始互相怀疑代码。在package.json里把版本写死用锁文件统一安装能避免大量无效沟通。CI 里也应该跑一次类型检查让版本差异在合入前就暴露出来。关于符号链接类的路径映射我建议只在确实需要大量映射时才用。有的项目会在tsconfig里定义十几个别名api、store、hooks、composables全都来一遍看起来很有条理实际上维护成本很高——每加一个别名就要改tsconfig和 Vite 两个文件还得记住每条映射对应哪个目录。我自己的做法是保留指向src剩下的靠相对路径和目录结构解决。目录命名足够清晰的话别名并没有想象中那么必要。关于检查脚本我的习惯是在package.json里加一条独立的类型检查命令比如type-check: vue-tsc --noEmit并且和构建命令分开。不要试图在构建流程里塞类型检查那会把构建速度拖慢好几倍而且失败信息也不如单独跑清晰。开发时用编辑器实时反馈提交前本地跑一次CI 里再跑一次作为兜底这个节奏比较舒服。最后说个关于配置调试的小技巧。当你不确定某条配置到底有没有生效时别猜直接跑tsc --showConfig它会把经过所有extends合并、按环境解析之后最终的完整配置打印出来。这个输出是最权威的包含了所有默认值和继承结果。我排查配置问题的第一步永远是它比翻文档快得多也比在编辑器里瞎试靠谱得多。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

mongoose的findOneAndUpdate、findAndModify返回更新后的数据:把new选项改到TaoToken统一Key通道验证 2026/10/1 14:46:18

mongoose的findOneAndUpdate、findAndModify返回更新后的数据:把new选项改到TaoToken统一Key通道验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
保姆级喂饭教程:什么是Skills?如何用Skills?从Claude Code到TaoToken的实战拆解 2026/10/1 14:46:18

保姆级喂饭教程:什么是Skills?如何用Skills?从Claude Code到TaoToken的实战拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
深圳24小时自助健身房解决方案实战:从系统架构到落地指南 2026/10/1 14:46:18

深圳24小时自助健身房解决方案实战:从系统架构到落地指南

深圳24小时自助健身房解决方案实战:从系统架构到落地指南 核心架构:构建无人值守的智能健身闭环 深圳作为一线城市,24小时自助健身房已成为解决“打工人”健身时间碎片化痛点的主流业态。一个完整的解决方案,核心在于通过物联网、…

阅读更多 →
工控现货生意经:库存管理、货源渠道与客户复购的实战指南 2026/10/1 14:46:18

工控现货生意经:库存管理、货源渠道与客户复购的实战指南

1. 工控现货这门生意,远不止“有货就卖”这么简单“工控现货”这四个字,在外行看来可能就是一个卖工业控制产品的店铺,跟卖手机、卖电脑的没什么本质区别。但真正在这个圈子里摸爬滚打过的人都知道,工控现货是一门极度考验供应链嗅…

阅读更多 →
工控现货生意经:从选型备货到库存管理的实战指南 2026/10/1 14:46:18

工控现货生意经:从选型备货到库存管理的实战指南

1. 工控现货到底是个什么生意干了十几年工业自动化这一行,我越来越觉得“工控现货”这四个字值得好好聊一聊。很多刚入行的朋友第一次听到这个词,脑子里浮现的画面可能是仓库里堆满了PLC、变频器、伺服电机,然后有人打电话来问“有没有现货”…

阅读更多 →
Agent运行时全链路实操:上下文管理与检查点设计 2026/10/1 14:46:04

Agent运行时全链路实操:上下文管理与检查点设计

1. 这不是概念课,是Agent运行时的“心跳图谱”——从上下文到资源管控的全链路实操解剖你有没有遇到过这样的情况:一个精心设计的Agent在测试环境跑得飞起,一上生产就频繁报错“agent execution terminated due to error.”,日志里…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉