咳咳,各位观众老爷,晚上好!我是你们的老朋友,今天咱就来聊聊 TypeScript 的 tsconfig.json 这个磨人的小妖精。别害怕,虽然它长得像个 JSON 文件,但其实蕴藏着巨大的能量,用得好,能让你的项目起飞,用不好…嗯,就只能疯狂 Google 了。
今天我们就从编译选项、路径别名和项目引用这三个方面,由浅入深,彻底搞懂它!
一、编译选项:TypeScript 的核心指令
tsconfig.json 最重要的部分,莫过于 compilerOptions 了。这里面塞满了各种编译选项,控制着 TypeScript 编译器如何将你的 .ts 文件转换成 .js 文件。 咱们挑几个最常用的,也是最容易让人懵逼的选项,好好说道说道。
-
target:目标 JavaScript 版本这个选项决定了你的代码要编译成哪个版本的 JavaScript。 常见的取值有
es5,es6,es2015,es2016,es2017,es2018,es2019,es2020,es2021,es2022,esnext。{ "compilerOptions": { "target": "es5" // 兼容老旧浏览器 } }选择
es5可以兼容很多老旧浏览器,但你就用不了 ES6+ 的新特性了。 如果你的项目面向现代浏览器,那es6甚至esnext都是不错的选择。esnext会编译成最新的 JavaScript 特性,但需要注意兼容性,可能需要配合 Babel 使用。 -
module:模块化方案这个选项指定了你的代码要使用哪种模块化方案。 常见的取值有
commonjs,amd,system,umd,es6,es2015,esnext,node16,nodenext。{ "compilerOptions": { "module": "commonjs" // Node.js 常用 } }commonjs是 Node.js 的模块化方案,用require和module.exports。es6或es2015使用import和export,是 ES 模块。umd是一种通用模块定义,可以在多种环境下使用。node16和nodenext针对 Node.js 的 ESM 支持进行了优化。 -
lib:包含的类型声明文件这个选项指定了你的项目要包含哪些内置的类型声明文件。
{ "compilerOptions": { "lib": ["es6", "dom"] // 包含 ES6 的类型声明和 DOM API 的类型声明 } }如果你用到了 DOM API,比如
document.getElementById,那就需要包含"dom"。 如果你想用 ES6 的Promise,那就需要包含"es6"或"es2015"。lib的取值有很多,可以根据你的项目需求进行选择。 -
allowJs:允许编译 JavaScript 文件如果你的项目里既有 TypeScript 文件,又有 JavaScript 文件,并且你想让 TypeScript 编译器也编译 JavaScript 文件,那就需要把这个选项设置为
true。{ "compilerOptions": { "allowJs": true // 允许编译 JavaScript 文件 } } -
checkJs:对 JavaScript 文件进行类型检查如果
allowJs为true,并且你还想让 TypeScript 编译器对 JavaScript 文件进行类型检查,那就需要把这个选项设置为true。{ "compilerOptions": { "allowJs": true, "checkJs": true // 对 JavaScript 文件进行类型检查 } } -
jsx:JSX 支持如果你的项目使用了 React 或其他 JSX 框架,那就需要设置这个选项。
{ "compilerOptions": { "jsx": "react" // 支持 React 的 JSX 语法 } }常见的取值有
react,react-native,preserve。react会将 JSX 转换成React.createElement调用。preserve会保留 JSX 语法,交给其他工具处理。 -
declaration:生成声明文件如果你的项目是一个库,并且你想发布到 npm 上,那就需要生成声明文件 (
.d.ts),方便其他开发者使用。{ "compilerOptions": { "declaration": true // 生成声明文件 } } -
sourceMap:生成 Source MapSource Map 可以将编译后的 JavaScript 代码映射回原始的 TypeScript 代码,方便调试。
{ "compilerOptions": { "sourceMap": true // 生成 Source Map } } -
outDir:输出目录指定编译后的 JavaScript 文件输出到哪个目录。
{ "compilerOptions": { "outDir": "./dist" // 输出到 ./dist 目录 } } -
rootDir:根目录指定 TypeScript 文件的根目录。
{ "compilerOptions": { "rootDir": "./src" // 根目录为 ./src } } -
strict:启用所有严格类型检查选项这是一个非常重要的选项,建议开启。 开启后,TypeScript 编译器会进行更严格的类型检查,可以帮助你发现潜在的错误。
{ "compilerOptions": { "strict": true // 启用所有严格类型检查选项 } }strict选项相当于同时开启了以下几个选项:noImplicitAny: 在表达式和声明上有隐含的any类型时报错。noImplicitThis: 在this表达式值为any的情况下报错。alwaysStrict: 以严格模式解析并为每个源文件生成"use strict"语句。strictNullChecks: 启用严格的null和undefined检查。strictFunctionTypes: 启用对函数类型的严格检查。strictBindCallApply: 启用对Function.prototype.bind、call和apply方法的严格检查。strictPropertyInitialization: 确保类的非 undefined 属性已在构造函数中初始化。
-
baseUrl和paths:路径别名baseUrl指定了模块解析的基准目录。paths用于配置路径别名。 后面我们会详细讲解。
二、路径别名:告别冗长的相对路径
在大型项目中,模块之间的引用关系错综复杂,经常会出现 ../../../../utils/helper 这种冗长的相对路径,让人头皮发麻。 这时候,路径别名就派上用场了。
通过配置 baseUrl 和 paths,你可以用更简洁的别名来代替冗长的相对路径。
{
"compilerOptions": {
"baseUrl": "./src", // 基准目录为 ./src
"paths": {
"@utils/*": ["utils/*"], // @utils/xxx 映射到 src/utils/xxx
"@components/*": ["components/*"] // @components/xxx 映射到 src/components/xxx
}
}
}
有了上面的配置,你就可以这样引用模块了:
import { helper } from "@utils/helper"; // 代替了 import { helper } from "../../../../utils/helper";
import { Button } from "@components/Button";
是不是清爽多了?
baseUrl 和 paths 配合使用,可以让你在项目中随意移动文件,而不需要修改大量的引用路径。 这对代码重构非常友好。
baseUrl 的作用
baseUrl 指定了模块解析的基准目录。 如果你没有设置 baseUrl,那么默认的基准目录是 tsconfig.json 所在的目录。
paths 的作用
paths 用于配置路径别名。 它的 key 是别名,value 是对应的路径。 可以使用 * 通配符来匹配多个文件。
paths 的 value 是一个数组,这意味着你可以配置多个路径。 TypeScript 编译器会按照数组的顺序依次查找,直到找到对应的模块。
例如:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"@api/*": ["api/mock/*", "api/*"] // 先查找 api/mock/xxx,再查找 api/xxx
}
}
}
配合 webpack 使用
如果你的项目使用了 webpack,还需要在 webpack 的配置中添加 resolve.alias:
module.exports = {
resolve: {
alias: {
"@utils": path.resolve(__dirname, "src/utils"),
"@components": path.resolve(__dirname, "src/components"),
},
},
};
这样 webpack 才能正确解析你的别名。
三、项目引用:大型项目的模块化利器
当你的项目变得越来越大,代码越来越多,编译速度也会越来越慢。 这时候,项目引用就派上用场了。
项目引用可以将一个大型项目拆分成多个小的子项目,每个子项目都有自己的 tsconfig.json 文件。 主项目可以通过引用子项目,来减少编译时间和提高代码的可维护性。
// tsconfig.json (主项目)
{
"compilerOptions": {
// ...
},
"references": [
{ "path": "./packages/component-a" },
{ "path": "./packages/component-b" }
]
}
// packages/component-a/tsconfig.json (子项目 A)
{
"compilerOptions": {
// ...
"composite": true // 必须设置为 true
},
"include": ["./src/**/*"]
}
// packages/component-b/tsconfig.json (子项目 B)
{
"compilerOptions": {
// ...
"composite": true // 必须设置为 true
},
"include": ["./src/**/*"]
}
在上面的例子中,主项目的 tsconfig.json 文件通过 references 字段引用了两个子项目:component-a 和 component-b。
每个子项目的 tsconfig.json 文件都需要设置 composite 为 true。 这表示这是一个可以被引用的项目。
当你编译主项目时,TypeScript 编译器会先编译子项目,然后再编译主项目。 如果子项目的代码没有发生变化,TypeScript 编译器会跳过子项目的编译,从而提高编译速度。
项目引用的优势
- 提高编译速度: 只编译修改过的子项目。
- 提高代码可维护性: 将大型项目拆分成小的子项目,方便管理。
- 代码复用: 子项目可以被多个项目引用。
项目引用的注意事项
- 子项目的
compilerOptions必须包含"composite": true。 - 主项目需要通过
references字段引用子项目。 - 子项目的输出目录 (
outDir) 应该避免重叠。
composite 选项
composite 选项表示这是一个可以被引用的项目。 开启 composite 选项后,TypeScript 编译器会生成 .d.ts 声明文件,方便其他项目引用。
incremental 选项
incremental 选项用于增量编译。 开启 incremental 选项后,TypeScript 编译器会缓存编译结果,下次编译时只编译修改过的文件。
incremental 选项需要配合 composite 选项使用。
总结
tsconfig.json 是 TypeScript 项目的核心配置文件,掌握它对于开发高质量的 TypeScript 项目至关重要。 希望今天的讲解能帮助你更好地理解 tsconfig.json 的配置,并在实际项目中灵活运用。
| 配置项 | 作用 |
|---|---|
target |
指定编译后的 JavaScript 版本,影响代码的兼容性。 |
module |
指定模块化方案,决定了代码如何组织和引用。 |
lib |
包含的类型声明文件,用于提供内置 API 的类型信息。 |
allowJs |
允许编译 JavaScript 文件,方便 TypeScript 和 JavaScript 混合开发。 |
checkJs |
对 JavaScript 文件进行类型检查,提高 JavaScript 代码的质量。 |
jsx |
JSX 支持,用于处理 React 或其他 JSX 框架的代码。 |
declaration |
生成声明文件,方便其他开发者使用你的库。 |
sourceMap |
生成 Source Map,方便调试。 |
outDir |
输出目录,指定编译后的 JavaScript 文件输出到哪个目录。 |
rootDir |
根目录,指定 TypeScript 文件的根目录。 |
strict |
启用所有严格类型检查选项,提高代码质量。 |
baseUrl |
模块解析的基准目录,用于配置路径别名。 |
paths |
路径别名,用于简化模块引用路径。 |
references |
项目引用,用于将大型项目拆分成多个小的子项目,提高编译速度和代码可维护性。 |
composite |
表示可以被引用的项目,必须与 references 配合使用。 |
incremental |
增量编译,缓存编译结果,下次编译时只编译修改过的文件。 |
好了,今天的分享就到这里。 希望大家都能成为 tsconfig.json 的调教大师! 如果有什么问题,欢迎在评论区留言,我们一起探讨。 拜拜!