tsconfig.json文件各字段吐血整理

tsconfig.json文件说明

一般在 typescript 的项目中,我们都能看到 tsconfig.json 这个文件,它指定了此项目的编译选项,也指定了此项目的根目录,因此这个文件一般也是在项目的根目录下。既然如此,就单单 typescript 项目而言,它的编译一般有以下几种方式:

  • 命令行直接输入 tsc 命令不带任何参数进行编译:

    此时编译器会从当前目录开始查找 tsconfig.json 文件,如果当前目录没有发现该文件,则逐级向父级目录搜索。如果一直没有检索到该文件,编译器会给出使用提示。

  • 命令行调用 tsc 带参数 --project(或 -p) 而指定一个目录:

    编译器直接在该目录下查找 tsconfig.json 文件,如果没找到则报错。

  • 命令行调用 tsc 后直接指定文件:

    直接编译指定的文件。

各字段说明

tsconfig.json 所包含的属性其实并不多,顶层属性只有几个。最重要的而且最多的应该属 compilerOptions 这个属性中的各个字段了。这个字段中的属性居多,而且 中文官网 讲述的很清晰。本篇文章重点来聊聊除此之外的顶层属性。

另外,需要注意的是,在命令行上指定的编译选项会覆盖在tsconfig.json文件里的相应选项。

1. files

数组类型,用于表示由 ts 管理的 文件 的具体路径,可以是相对或绝对路径。这些文件内部有依赖的模块(或者引入了哪些模块),编译器也会搜索到依赖模块进行编译。如果某些模块并没有在项目中引入,虽然在项目目录中也不会被编译。需要注意的是,files 中不支持 glob 匹配模式的路径。

2. include 与 exclude

数组类型,include 用于表示 ts 管理的文件。exclude用于表示 ts 排除的文件(即不被编译的文件)。其中的文件列表可以使用 glob 匹配模式列表,支持的glob通配符有:

  • * 匹配0或多个字符(不包括目录分隔符)
  • ? 匹配一个任意字符(不包括目录分隔符)
  • **/ 递归匹配任意子目录

注意,这三者的优先级是这样的:files > exclude > include 。如果不指定 files ,项目目录下的所有文件都会被编译器编译。如果同一个文件在三者中均指定,此文件一定会被编译器编译。而 files 中不指定而在 excludeinclude 中同时指定的文件也会被编译,因为优先级是这样的 exclude > include 。另外,exclude默认情况下会排除node_modulesbower_componentsjspm_packagesoutDir 目录。

3. compileOnSave

布尔类型,可以让 IDE 在保存文件的时候根据 tsconfig.json 重新生成编译后的文件。

4. extends

字符串类型,该值是一个路径,指定另一个配置文件用于继承 tsconfig.json 中的配置。在原文件里的配置最先被加载,原文件里的配置被继承文件里的同名配置所重写。 如果发现循环引用,则会报错。

5. typeAcquisition

对象类型,设置自动引入库类型定义文件。acquisition 翻译过来是 “获得物、获得” 的意思。在整个项目中,如果存在用JavaScript写的库,ts 会自动去 compilerOptions.typeRoots 指定的目录中寻找对应的类型声明文件。这个行为被称为 typeAcquisition (类型获得)。这个行为可以通过enable来开启或关闭,且以库级别来指定应用的范围。但我在实践中,通过指定 enable 的值去控制这个行为并未有明显的感官,即使使用 vscode 修改配置后重启也并未生效。

当我使用 jquery 做测试的时候,将 enable 设为 false 且下载了 @types/jquery 的时候,vscode 并未提示无法找到该声明,也无任何报错。但当我将其设为 true,且删除 @types/jquery时,vscode 仍未提示无法找到该声明,鼠标悬浮引入的 jquery 提示在全局的 typescript/3.8/node_modules/@types/ 目录下找到了该声明。

这个配置项在平时的开发中并不常用,大家也不必深究。

6. watchOptions

对象类型,typescript3.8 以上新增加的配置,用来配置使用哪种监听策略来跟踪文件和目录。由于 tsc 的监听文件机制依赖于 nodefs.watch/fs.watchFile。这两种方法的实现并不相同,前者是采用文件系统的事件做到通知,而后者使用轮询的机制。更多可以查阅 node 官方文档。

  1. watchFile

    字符串类型,配置单个文件的监听策略,必须为一下几个值:

    • useFsEvents(默认):采用系统的文件系统的原生事件机制监听文件更改

    • useFsEventsOnParentDirectory:采用系统的文件系统的原生事件机制监听修改文件所在的目录,这样修改一个文件实际上监听的是此文件所在的目录都被监听了,如此整个项目的文件监听器将显著减少,但可能导致监听并不准确。

    • dynamicPriorityPolling:创建一个动态队列去监听文件,修改频率较低的文件将被减少轮询监听的频率。

    • fixedPollingInterval:固定间隔的检查每个文件是否发生变化。

    • priorityPollingInterval:固定间隔的检查每个文件是否发生变化,但使用启发式监听的文件的检查频率要低于非启发式监听的文件。

  2. watchDirectory

    字符串类型,配置监听目录的策略,必须为以下几个值:

    • useFsEvents(默认)
    • dynamicPriorityPolling
    • fixedPollingInterval

    以上三个和 watchFile 中相差不多

  3. fallbackPolling

    当采用系统的文件系统中原生事件机制监听文件时,此选项指定本机的文件监听器被耗尽或者不支持本机文件监听器是编译器采用的轮询策略,可以设置为以下几个值:

    • fixedPollingInterval
    • dynamicPriorityPolling
    • priorityPollingInterval
    • synchronousWatchDirectory:禁用对目录的延迟监听。如果有大量的文件更改,比如在 npm installnode_modules 目录发生的变化,延迟监听是非常有用的。但总有些不常见的场景需要禁用延迟监听。
  4. synchronousWatchDirectory

    布尔类型,是否对目录延迟监听。如果配置为 true ,当文件发生修改时同步的调用回调并更新目录监听器。

  5. excludeFiles

    字符串数组,用于指定不需要被监听变化的文件

  6. excludeDirectories

    字符串数组,用于指定不需要被监听变化的目录

7. reference

项目引用是 TypeScript 3.0的新特性,它支持将 TypeScript 程序的结构分割成更小的组成部分。

这是 typescript 官网中的描述,那怎么理解这句话呢。我们通过一个场景认识新出这种的 reference 特性。

假设我们要开发一个类似于 lodash 的工具库,并在项目中使用,而且后期很有可能还要在业界推广。为了保证这个工具的顺利开发及推广,我们必须要做相应的单元测试。那这个工具库可以看做一个项目,对其中的每个功能的测试也可作为一个独立的项目。但整个过程中,工具库的开发和测试应该是属于同一个项目下 “分项目” 的。那这种情况下 reference 就很棒了。首先我们搭一个目录出来:

|---- src/
    |---- index.ts    // 整个工具库的入口
    |---- copyDeep.ts // 其中定义了copyDeep方法
|---- test/
    |---- copyDeep.test.ts // copyDeep的单元测试
|---- package.json
|---- tsconfig.json

copyDeep.test.ts 中肯定要引用 src/copyDeep,也就是说 test 的项目是依赖于 src 的。如果 src 中的代码发生了变化,整个工具库项目应该重新编译,而 test 项目不应该再被编译,这本来就是合理的。如果 test 项目中的代码发生了变化,那 test 项目应该被重新编译,而 src 项目不应该再被编译。如何在一个项目中配置而做到分别编译相应的子项目呢?首先最先想到的应该是在 tsconfig.json 文件中引入 include 字段配置,我们先尝试一下下面的配置:

{
    "files": [
        "./src/index.ts"
    ],
    "include": [
        "./test/**/*.test.ts"
    ],
    "compilerOptions": {
        "outDir": "./dist/"
    }
}

我们来分析这样配置的会有哪些问题:

  1. 首先,从整个项目层面,确实做到了修改任意文件重新编译的功能。但注意,编译的是全量的 ts 文件。
  2. 随着日后项目的增大,在 *.test.ts 文件中引入也将逐渐变大。
  3. 修改了 src//**/*.ts 的内容,test/**/*.ts 也将作为输出,这是我们不希望看到的。

此时,reference 将解决上述的每一个问题,我们修改项目结构如下:

|---- src/
    |---- index.ts      // 整个工具库的入口
    |---- copyDeep.ts   // 其中定义了copyDeep方法
    |---- tsconfig.json // 工具库的编译配置文件
|---- test/
    |---- copyDeep.test.ts  // copyDeep的单元测试
    |---- tsconfig.json     // 测试的编译配置文件
|---- package.json
|---- tsconfig.json

并修改为以下配置:

// 根目录下的 /tsconfig.json
{
    "compilerOptions": {
        "declaration": true, // 为子项目生成.d.ts声明文件
        "outDir": "./dist",
    }
}

// src目录下的 /src/tsconfig.json
{
    "extends": "../tsconfig",
    "compilerOptions": {
        "composite": true // 必须设置为true,表明该文件夹为一个子项目
    }
}

// test目录下的 /src/tsconfig.json
{
    "extends": "../tsconfig",
    "references": [
        { "path": "../src" } // 表示引用了工具库项目
    ]
}

这样配置后,如果 src 项目已经编译完成并且输出了编译后的文件, 那在 test 项目中,实际加载的是 src 项目声明的 .d.ts 文件,而且这个声明文件是对 test 项目可见的。另外,如果开启了 watch 模式,修改了内容只会编译相应的项目而不会全量编译。这会显著的加速类型检查和编译,减少编辑器的内存占用。而且在代码结构层命有了一个很清晰的规划。

总结来讲,refrence 的作用是将两个项目关联起来作为一个项目开发,当某个项目代码修改后还能单独编译相应的项目而不是整个项目。再说的简单点,就是实现了关联项目间的懒编译。

总结

本篇文章先到这里,总结一下:tsconfig.json 这个文件是用来界定 ts 项目的根目录,也用来配置 tsc 在编译 ts 文件时的一些选项。files、exclude、include 用来配置需要编译哪些文件;compilerOnSave 是指定 IDE 保存后是否重新编译的;extends 用来扩展当前的配置;扩展配置文件中的字段会覆盖当前文件的相同字段;typeAcquisition 用来指定某些库的类型声明文件,如:

"typeAcquisition": {
  "jquery": "@/types/jquery"
}

watchOptions 用来配置 tsc 的监听策略;reference 指定关联项目,从而提高编译速度。

另外:

文中若有表述不妥或是知识点有误之处,欢迎留言批评指正,共同进步!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容