在使用Vite创建项目时使用的是vue-ts模板,所以在创建项目的时候package.json就自带了typescript。
在初始化 vite 项目的时候就可以看到,项目根目录下生成了 tsconfig.json 和 tsconfig.node.json 两个文件。
1.tsconfig.json 配置项
在初始化 vite 项目的时候可以看到,项目根目录下生成了 tsconfig.json 和 tsconfig.node.json 两个文件。
tsconfig.json 指定了用来编译这个项目的根文件和编译选项
{"compilerOptions": {"target": "esnext","useDefineForClassFields": true,"module": "esnext","moduleResolution": "node","strict": true,"jsx": "preserve","sourceMap": true,"resolveJsonModule": true,"esModuleInterop": true,"lib": ["esnext", "dom"]},"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],"references": [{ "path": "./tsconfig.node.json" }]}
可以看到tsconfig.node.json中的"include": ["vite.config.ts"]表明这个单独拆分出来的配置文件只是负责编译 vite 的配置文件vite.config.ts
{"compilerOptions": {"composite": true,"module": "esnext","moduleResolution": "node"},"include": ["vite.config.ts"]}
include 指定需要编译的文件范围
默认是对 src 目录下的.ts、.d.ts、.tsx、.vue结尾的文件都需要进行编译,这里扩展下和src同级的tests、build目录(如果项目中需要的话)
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "build/**/*.ts", "tests/**/*.ts", "tests/**/*.tsx"]
exclude 配置不需要编译的文件范围
"exclude": ["node_modules", "tsconfig.json", "dist"]
references 将 TypeScript 程序拆分
references 是 TypeScript 3.0 的新特性,允许将 TypeScript 程序拆分结构化。这和我们写 vue 组件的思想有着异曲同工之妙,避免了在一个文件中处理过多的内容,而是通过拆分成多个文件,分别配置不同的部分,达到更加清晰,可维护性更高的目的。
这里我们可以不拆分,可以删除掉tsconfig.node.json统一用tsconfig.json,并移除默认的:
"references": [{ "path": "./tsconfig.node.json" }]
compilerOptions 编译选项
useDefineForClassFields
useDefineForClassFields 是 TypeScript 3.7.0 中新增的一个编译选项,启用后的作用是将 class 声明中的字段语义从 [[Set]] 变更到 [[Define]]
skipLibCheck 忽略声明文件检查
忽略所有的声明文件( *.d.ts)的类型检查
"compilerOptions": {"skipLibCheck": true}
这个属性不但可以忽略 npm 不规范带来的报错,还能最大限度的支持类型系统。设置为 true 就不用怕使用的第三方库不规范了。
为什么要跳过这些第三方库的检查?
我们做类型检查(以及代码规范等)的目的是为了对团队内业务代码开发保持统一和规范,以保证开发成员之间的快速上手和后续维护。所以我们要做的是将各种规则集成到业务代码模块,而一些框架上的或者第三方库的内容就不用多此一举了。
baseUrl
作用:设置baseUrl来告诉编译器到哪里去查找模块。所有非相对模块导入都会被当做相对于 baseUrl。
注意相对模块的导入不会被设置的baseUrl所影响,因为它们总是相对于导入它们的文件.
这个设置的作用和 vite 构建选项 build 中的 base 是类似的,我们配置为当前根目录即可
paths 路径映射列表
作用:模块名到基于baseUrl的路径映射的列表。
请注意"paths"是相对于"baseUrl"进行解析。
在 vite 配置中设置了路径别名resolve.alias,为了让编译 ts 时也能够解析对应的路径,我们还需要配置 paths 选项
"paths": {"@/*": ["src/*"],"utils/*": ["src/utils/*"],"api/*": ["src/api/*"],"components/*": ["src/components/*"],"views/*": ["src/views/*"],"#/*": ["types/*"],"build": ["build/*"]},
isolatedModules 将每个文件作为单独模块
typescript 将没有导入/导出的文件视为旧脚本文件。因为这样的文件不是模块和它们在全局命名空间中合并的任何定义。该配置项会禁止此类文件。将任何导入或导出添加的文件都视为模块
这个设置在 vite 官方文档中是被要求应该设置为 true 的,但(vite2)项目初始化的时候并没有默认加上这条(vite3加上了)
"isolatedModules": true,

https://vitejs.cn/guide/features.html#typescript-compiler-options
types 客户端类型
作用:添加要包含的类型声明文件名列表,只有在这里列出的模块的声明文件才会被加载进来
{"compilerOptions": {"types": ["vite/client"]}}
这将会提供以下类型定义补充:
- 资源导入 (例如:导入一个 .svg 文件)
- import.meta.env 上 Vite 注入的环境变量的类型定义
- import.meta.hot 上的 HMR API 类型定义
tsconfig.json文件首行报错
vscode会自动进行文件的语义检查。因为自定义的tsconfig.json文件无法覆盖vscode自带的配置,所以会报错。
打开配置settings.json文件,让自定义的jsconfig.js文件覆盖vscode默认选项。
3.2. env.d.ts 全局类型声明
打开 src 文件夹下的 env.d.ts(vite3为vite-env.d.ts)文件,可以看到
/// <reference types="vite/client" />declare module '*.vue' {import type { DefineComponent } from 'vue'// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-typesconst component: DefineComponent<{}, {}, any>export default component}

请注意:三斜杠指令是包含单个XML标签的单行注释,注释的内容会做为编译器指令使用,只有在文件的最顶部才会生效,可以查看TypeScript: Documentation - Triple-Slash Directives学习相关内容。
所以这个文件的作用就呼之欲出了:帮助编译器识别类型。
TypeScript 相比 JavaScript 增加了类型声明。原则上,TypeScript 需要做到先声明后使用。这就导致开发者在调用很多原生接口(浏览器、Node.js)或者第三方模块的时候,因为某些全局变量或者对象的方法并没有声明过,导致编译器的类型检查失败。
当我们遇上Property xxx does not exist on type …报错的时候,就可以定位到是没有声明过这个方法/属性。我们就可以在这个文件作全局声明。
可以看到,该文件已经默认为所有的 vue 文件声明了 DefineComponent的组件类型,这就意味着只要我们的单文件组件使用
<script lang="ts">import { defineComponent } from 'vue'export default defineComponent({...})</script>
的写法,就能避免 vue 文件中大多数类型声明的报错,比如使用路由的this.$router、this.$route命令
2. 完整配置文件
原代码
{"compilerOptions": {"target": "ESNext","useDefineForClassFields": true,"module": "ESNext","importHelpers": true,"moduleResolution": "Node","experimentalDecorators": true,"allowSyntheticDefaultImports": true,"strict": true,"jsx": "preserve","sourceMap": true,"resolveJsonModule": true,"isolatedModules": true,"esModuleInterop": true,"baseUrl": ".","types": ["vite/client"],"noEmit": true,"paths": {"@/*": ["src/*"],"utils/*": ["src/utils/*"],"api/*": ["src/api/*"],"components/*": ["src/components/*"],"#/*": ["types/*"],"build": ["build/*"]},"lib": ["ESNext", "DOM"],"skipLibCheck": true,"typeRoots": ["./node_modules/@types/", "./types"]},"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "build/**/*.ts", "tests/**/*.ts", "tests/**/*.tsx"],"exclude": ["node_modules", "tsconfig.json", "dist"]}
带注释代码
{"compilerOptions": {// ↓指定ECMAScript目标版本,esnext为最新版本"target": "ESNext",// ↓将 class 声明中的字段语义从 [[Set]] 变更到 [[Define]]"useDefineForClassFields": true,// ↓指定生成哪个模块系统代码,esnext为最新版本"module": "ESNext","importHelpers": true,// ↓决定如何处理模块。"moduleResolution": "Node",// ↓启用实验性的ES装饰器。"experimentalDecorators": true,// ↓允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查。"allowSyntheticDefaultImports": true,// ↓启用所有严格类型检查选项。"strict": true,// ↓在 .tsx文件里支持JSX"jsx": "preserve",// ↓有未使用的局部变量抛错。// "noUnusedLocals": true,// ↓有未使用的参数抛错。// "noUnusedParameters": true,// ↓生成相应的 .map文件。"sourceMap": true,"resolveJsonModule": true,//将每个文件作为单独模块"isolatedModules": true,"esModuleInterop": true,// ↓解析非相对模块名的基准目录。"baseUrl": ".",// ↓要包含的类型声明文件名列表。"types": ["vite/client"],"noEmit": true,// ↓模块名到基于 baseUrl的路径映射的列表。"paths": {"@/*": ["src/*"],"utils/*": ["src/utils/*"],"api/*": ["src/api/*"],"components/*": ["src/components/*"],"views/*": ["src/views/*"],"#/*": ["types/*"],"build": ["build/*"]},// ↓编译过程中需要引入的库文件的列表。"lib": ["ESNext", "DOM"],// ↓忽略所有的声明文件( *.d.ts)的类型检查。"skipLibCheck": true,// ↓要包含的类型声明文件路径列表。"typeRoots": ["./node_modules/@types/", "./types"],},// ↓指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "build/**/*.ts", "tests/**/*.ts", "tests/**/*.tsx"],// 指定一个排除列表(include的反向操作)"exclude": ["node_modules", "tsconfig.json", "dist"]}
