赞
踩
大家好,我是前端西瓜哥。
tsconfig.json 是用来配置 TS 编译选项的,通常位于项目的根目录位置。
我们可以用 ts 提供的 tsc 命令行工具,执行 tsc --init
。
$ tsc --init
Created a new tsconfig.json with:
TS
target: es2016
module: commonjs
strict: true
esModuleInterop: true
skipLibCheck: true
forceConsistentCasingInFileNames: true
You can learn more at https://aka.ms/tsconfig
然后我们就能得到一个默认的 tsconfig.json 文件,且这是一种可以添加注释的 json 文件。
里面有很多带有注释的选项,目的是让开发者能够反注释快速启用一些配置。
但注释的选项太多了,所以我将它们移除了,得到下面的默认配置:
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"module": "commonjs", /* Specify what module code is generated. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
"strict": true, /* Enable all strict type-checking options. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}
首先我们看配置最上层级的配置字段。
compilerOptions:编译器相关的选项。比如配置编译成 ES5,模块化使用 commonjs 等。这里的编译配置很多,后面我们会讲解一些常用的配置;
files:指定需要被编译的文件列表。这里不能指定目录,只能是文件,可以省略 .ts
后缀。适合需要编译的文件比较少的情况。默认值为 false;
include:指定需要编译的文件列表或匹配模式。include 可以通过通配符指定目录,如 "src/**/*"
表示 src 下的所有文件。如果没有指定 files 配置,默认值为 **
,即项目下所有文件;如果配置了 files,默认值为 []
空数组;
exclude:在 include 圈定的范围内,排除掉一些文件。我们经常用它来排除编译输出目录、测试文件目录、一些生成文件的脚本等文件。默认值为 “node_modules,bower_componen”;
extends:继承另一个 ts 配置文件。这在 monorepo 的代码组织中非常有用,不同的 package 可以通过 extends 继承通用的 ts 配置。用法示例:"extends": "./common-tsconfig.json"
。
reference:引用。项目中如果有多个相互独立的模块,可以使用这个属性来做分离。这样一个模块改变后,就只重新编译这个模块,其他模块不重新编译。编译时要改用 tsc --build
。这在非常大的项目中应该能有不小收益。
需要注意的是,files、include、exclude 只是指定编译的入口文件范围,如果其中的文件 import 了范围外的 ts 文件,范围外的文件依旧会被编译。
在 VSCode 下,范围外的 ts 文件不会应用项目下的 tsconfig.json 配置。
接下来我们就来看看 compilerOptions 下的常用配置属性。
因为配置项实在很多,我就挑一些比较基本的进行讲解。
指定编译的目标版本。
tsc 也可以像 babel 一样,可以将高版本的 TS / JS 编译为低版本。你看这个 tsc 脚本多大。
target 用于指定 TS 最后编译出来的 ES 版本,默认值是 ES3。
对于一些高版本引入的新 API 并,tsc 不会注入 polyfill,你需要自己全量引入 core-js,这点还是 babel 提供的按需引入 core-js 要更好一些。
当然其他的不能 polyfill 的实现,tsc 还是会做处理的。比如箭头函数转换为普通函数,async / await 转换为一大坨的等价代码。
说实在的,ES3 实在有够古老的,很多 API 都不支持,个人觉得默认为 ES5 比较好。
我想大概是历史原因,因为 TS 发布那会,ES6 还没出来,只有 ES5 编译成 ES3 这一种情况。现在虽然 ES5 已经广泛支持了,但为了兼容还是保持默认的 ES3。
target 支持的值有:es3、es5、es6(也叫 es2015)、es2016 一直到 es2022、然后还有 esnext。没有 es7 这种东西,你得用 es2016。另外,esnext 指的是当前版本的 TS 编译器支持的最高版本。
这些值是大小写敏感的,可以是 es5、ES5,或大小写混杂。
通常来说前端项目会使用 es5。后端项目就看 nodejs 的版本支持 ES 的程度,像 Nestjs 脚手架生成的项目,taget 指定为 es2017。
TypeScript 默认自带通用的 JS 内置 API 的类型声明,比如 Math、RegExp 等。
但 JS 运行的环境各种各样,会有一些特有的全局对象,比如浏览器下的 document,新的 ES 版本引入的新的 API。
为此,我们可以用 lib 这个属性来设置需要引入的全局类型声明。
lib 有高层级的:ES5
、ES2015
、DOM
、ESNEXT
、WebWorker
、ScriptHost
等。或是低层级模块的 DOM.Iterable
、ES2015.Core
、ES2017.TypedArrays
、 ES2018.Intl
等。高层级通常是多个全局类型声明的组合。
lib 的默认值通过 target 来指定,比如你的 target 指定为 ES7,它就会引入 ES7 的全局类型(大概是 lib.es2016.full.d.ts
)。
但如果你想用最新版本的 ES 语法,但希望它能编译成兼容性良好的 ES5,你就要手动设置 lib,像下面这样:
"target": "ES5",
"lib": [
"DOM",
"DOM.Iterable",
"ESNext"
]
lib 可以引入的全局类型声明文件都在这个目录下:
https://github.com/microsoft/TypeScript/blob/main/lib
启用严格模式,能够更能保证类型检测的正确。
将 strict 设置为 true,会开启一系列的严格的类型检验配置。
比如 strictNullChecks
配置的默认值会变成 true。这样一些对象类型就不能赋值为 undefined 或 null,就能一定程度阻止 obj.prop
可能导致的 Cannot read properties of undefined
的运行时错误。
还比如 strictBindCallApply
默认值变成 true。此时,对函数使用 bind、call、apply,参数类型必须和原函数类型相同。如果是 false,则可以是任何类型。
此外还有很多其他的和严格模式相关的配置也会开启。
建议开启 strict,能减少 bug,缺点是要多写一些类型推断和分支判断的代码。
baseUrl 用于设置基础 url,可以帮我们省掉一些多余的路径前缀。
比如我们原来要写长长的:
import { Login } from "./src/features/user/login";
但如果我们设置 baseUrl 为 ./src
,我们使用绝对路径时就能去掉重复的前缀,将路径写短一些:
import { Login } from "features/user/login";
相对路径不需要 baseUrl,因为它是相对于当前文件路径计算的。
./src
的 .
为 tsconfig.json 配置文件所在的目录路径。其实写成 src
也可以,它和 ./src
是等价的。
如果你不设置 baseUrl,模块文件 import 需要使用相对路径,或绝对路径(不是针对项目根目录的绝对路径,而是完整的路径)。
如果你想使用相对项目根目录的路径,你需要将 baseUrl 设置为 .
。
路径重映射。
要使用 paths,首先要设置好 baseUrl,paths 的源路径和新路径会使用 baseUrl 作为相对路径计算。
"baseUrl": "./src",
"paths": {
"@lib/*": ["./other/_lib/*", "./other/_lib2/*"]
},
上面的配置,是将 other/_lib
和 other/_lib2
路径重映射为 @lib
。
这里的 @
并不是必须的,这样写只是表明这个路径是一个重映射,或者叫别名,实际上文件系统上不存在对应的真实目录。
这样,原来比较冗长的路径:
import LibA from "other/_lib/lib_a";
就可以改为:
import LibA from "@lib/lib_a";
是否给每个编译出来的 JS 生成对应的 d.ts 类型声明文件。
TS 编译后变成的 JS 是不携带类型信息的。如果你想要保留信息,就需要一个 d.ts
文件来描述对应的 JS 文件。
我们用 NPM 安装的第三方包,这些包下的 package.json 文件的 types 属性,就指定了这个包的类型文件。如果没有显式提供 types 属性,则使用默认的 index.d.ts
。
指定编译生成的类型声明文件输出的目录。不提供的话,默认和生成的 js 文件放在一起。
"declarationDir": "./types"
编译文件的输出目录,默认为 .
,即项目根目录。如果不设置它,编译后的文件就会和源文件混杂在一起。通常我们会将 outDir 设置为 "./dist"
。
将所有 ts 文件合并编译生成一个 js 文件和它的类型声明 d.ts 文件。
这个配置项很少用,因为它只能用在不支持模块化导入的系统,即所有的 ts 文件都是全局的。
换句话说,module 配置项需要为 None、System 或 AMD。
"outFile": "./app.js"
编译后的 JS 使用哪种模块系统。
模块系统常用的有两种:ESModule 和 CommonJS。前者是 ES 的标准(使用了 import 关键字),后者则是 Nodejs 的使用的模块系统(使用了 require)。此外还有 AMD、UMD 等。
支持的值有:none、commonjs、amd、umd、system、es6/es2015、es2020、es2022、esnext、node16、nodenext。
它们的具体不同可以看官方文档的代码示例:
https://www.typescriptlang.org/tsconfig#module
如果 target 是 ES3 或 ES5,默认值是 CommonJS(毕竟 ES6 后才有的 ESModule);否则为 ES6/ES2015。
将 js 文件也作为编译对象,可以被 ts 文件引入。布尔值,默认为 false。
类型声明的一种引入方式是 @types 包,比如 React 框架使用了 flow 作为类型系统,为了支持 TypeScript,React 团队又写一套 d.ts 类型文件,发布到 @types/react
包上。
然后我们下载这个类型包后,并使用类似 import React from 'react'
,TS 会从从 node_modules/@types
中找到 react 文件夹,如果找不到,就会向上一层目录继续找,知道找到位置。如果存在,这个 React 对象就会被赋予声明的类型。
@types 可以是模块类型声明(像 React 类型),也可以是全局类型声明(如 nodejs 的 process 对象类型)。
types 配置 可指定只使用哪些全局类型声明,而不是 node_modules/@types 下所有的类型声明。如:
"lib": [
"node", // 即 node_modules/@types/node
"jest"
]
前面说到 ts 会递归查找 node_modules/@types
去寻找类型声明文件。
但你也可以用 typeRoots 来 指定只寻找特定目录下的类型声明文件,如:
"typeRoots": ["./typings", "./vendor/types"]
tsconfig 的配置非常多,但我想基本上掌握上面这几个配置的使用就差不多了。
更多的配置项可以看官方文档,建议自己构建一个 TS 项目进行测试。
我是前端西瓜哥,欢迎关注我,学习更多前端知识。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。