在使用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-types
const 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"]
}