解读 TS 的配置文件

1,863 阅读5分钟

tsconfig.json 是 TypeScript 的配置文件,可以使用 tsc --init 命令初始化,本篇文章会按照这个命令生成的配置顺序进行解读。

ps: TypeScript 版本是 4.3.4

incremental

开启了这个参数后,我们能在编译结果的同级目录看到一系列后缀名是 .tsbuildinfo 的文件,这个参数可以把我们上次编译的结果缓存到硬盘中,以便下次编译的时候使用。

tsBuildInfoFile

就像我们上一条讲的那样,开启 incremental 后,会生成一些默认后缀名是 .tsbuildinfo 的文件,而这个参数,可以用来指定生成的文件叫什么名字。

target

TS 作为一门静态类型检测语言,它只能帮我们在代码运行前找出错误,最后还是要编译成 JS 去运行,至于编译成哪个版本的 JS,就要靠这个参数来指定了。

module

用来切换包管理系统,我们可以根据要开发什么类型的项目,设置不同的值,比如开发 Node.js 项目就会设置为 'commonJS'。

我们通过举一个例子来看这个配置会产生什么影响,如果我们在 TypeScript 文件中写了这样两行代码:

import { age } from "./constants";

console.log(age)

当我们把 module 的值设置为 'commonJS' 时,编译的结果长下面这样:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("./constants");
console.log(constants_1.age);

当我们把 module 的值设置为 'ESNext' 时,编译的结果就没什么变化了:


import { age } from "./constants";

console.log(age)

allowJs

默认情况下,TypeScript 只能引入 .ts.tsx 的文件,开起来这个后,我们还能引入 .JS 的文件。

// @filename: foo.js
export const foo = () => {
    console.log('hi')
};


// @filename: index.ts
import { foo } from "./foo";
foo()

checkJs

这个参数要和 allowJs 配合着使用,如果开启了这个参数,在 JS 中有了错误,也会提示给我们。但是根据个人经验,混杂 JavaScript 和 TypeScript 的项目,比较难开启这个参数。

JSX

指示要使用哪种方式转换 JSX 语法,只针对 .tsx 文件进行解析。

以前的 Web 应用中, React 中的 JSX 直接被转换为 React.createElement 的形式,在 React 17 中,开发人员对 JSX 的转换进行了优化,通过这个参数,我们就能指定要选择哪种 JSX 的转换方式。参考链接

declaration

开启这个命令后,会生成 d.ts,如果我们使用 TypeScript 开发一个包,并且需要在 JavaScript 的环境下使用。这个时候生成 .d.ts 文件就能让我们在 JavaScript 的环境下也得到很好的代码提醒功能。

declarationMap

这个命令是配合着生成的 .d.ts 文件使用的,在未开启之前,我们使用编辑器寻找方法的定义(ctrl + 鼠标右键)会找到对应的接口定义,开启了这个属性,就可以帮我们找到真正的方法。

sourceMap

帮助我们在控制台调试的时候可以调试 TypeScript 代码。

outFile

会把所有的文件打包到我们指定的文件里,但是它不能在 CommonJS 和 ESM 中使用,我们就不做过多介绍了。

outDir

指定转换结果的目录,比如,我们指定把 .ts 文件的转换结果都放置到 dist 目录:

{
    outDir: './dist'
}

removeComments

是否移除转译的 JavaScript 代码中的注释。

noEmit

开启这个参数后,不会转译 JavaScript 代码,不会生成 SourceMap,也不会生成 .d.ts 文件。我们可能在配合 babel 的时候使用,这个时候可能只把 TypeScript 当做一个类型检测器,除此之外的工作都扔给 babel。

downlevelIteration

开启后,可以帮我们转译新的语法,以便旧的浏览器也可以支持,功能类似于 babel 。

比如下面这段代码:

const str = "Hello!";
for (const s of str) {
  console.log(s);
}

会转译成:

"use strict";
var str = "Hello!";
for (var _i = 0, str_1 = str; _i < str_1.length; _i++) {
    var s = str_1[_i];
    console.log(s);
}

importHelpers

开启 downlevelIteration 后会有一个问题,多个地方使用了同一个新语法,是不会合并到一块的,这就造成了代码的冗余,拿我们上面的例子来说,如果我们项目中 2 个地方使用到了 for...of,那上面那段转译结果就会出现两次。

如果我们开启了 importHelpers ,碰到了新语法,我们不会直接转译它,而是会从 tslib 这个包里去引入这个方法的 polyfill ,这样就解决了这个问题。当然了,这个时候就要确保我们项目里安装了 tslib 这个包了。

更多示例,参见:这个链接

noEmitOnError

写过 TS 的同学可能遇到过类型写得不对,webpack 就无法继续编译的场景。假如我们想把 一个可以正常运行的 JS 文件改为 TS 的,遇到的最大障碍就是类型报错了,就像下面这段代码,在 JS 中可以运行:

function greet(person) {
    console.log(person.toUpperCase())
}

但是如果我们把这个文件的后缀名改为 「.ts」, 并把 noImplicitAny 属性开启后,TS 就会报错,如果我们没有时间去修补所有的 TS 报错,还想编译的话,就可以关闭掉这个属性。反之,就要开启这个属性。

这个属性在迁移老的 JS 项目为 TS 项目时很有用。

strictNullChecks

如果不开启这个属性,我们可以写像下面这样的代码。尽管下面这种写法会在运行时报错,但是也可以通过 TS 的检测的:

function doSomething(x: string | null) {
    console.log("Hello, " + x.toUpperCase());
}

doSomething(null)

如果开启了这个属性,我们就只能在 x 为 string 类型的时候调用 toUpperCase 方法:

function doSomething(x: string | null) {
  if (x === null) {
    // do nothing
  } else {
    console.log("Hello, " + x.toUpperCase());
  }
}

如果少了对 xnull 的判断,TS 会报错,如果有同学嫌麻烦就是不想写,可以使用类型断言:

x!.toUpperCase() 

但是这么写一定要小心,它并不会帮我们排除 null,只是我们以这种写法显示的告诉 TS,它不会 null,所以就不会报错了。