Skip to content

TypeScript 配置管理

编译选项

我们通过 pnpm install -g typescript 下载的包会附带一个 bin/tsc,这就是实际上会使用的 TypeScript 编译器,他的参数可以大体分为输入文件和编译选项两种。如果仅指定了输入文件,就会在指定文件的同目录下编译出同样功能的 JavaScript 代码。之后我们也可以通过编译选项来调整编译器的行为,而这也是我们最需要关注的地方。

编译选项分为 长名称短名称 两种风格,其中长名称风格的选项会覆盖更广,而短名称只是长名称的缩写,仅仅为了方便使用,可读性和可维护性并不如长名称风格的编译选项。我们下面列出一些常用的编译选项:

编译选项名称功能描述
-h --help展示帮助文档
-d --declaration生成类型描述文件,通常库模块会使用该选项来提高用户体验
-m --module指定编译后的 JavaScript 代码使用什么模块类型,可选包括 CommonJSAMDESNext
-p --project指定使用的 tsconfig.json 文件路径
-t --target指定编译后的 JavaScript 版本,包括 ES3(默认),ES5ESNext
-w --watch在观测模式下进行编译
--strict启用严格模式,这是一系列的编译选项的总和,一般在 tsconfig 中指定

配置文件(tsconfig.json

1.5 版本之后,TypeScript 推出了配置文件的方式来管理工程,在这个配置文件中,能够指定

  1. 输入输出文件路径及格式
  2. 编译选项
  3. 继承配置位置
  4. 工程之间的引用关系

我们首先了解 tsc 是如何找到这个配置文件的,仅输入 tsc 命令时,它先从我们当前指令运行所在的目录开始找起,然后逐级向上,直到家目录下停止,如果还没有找到,则停止编译。我们可以通过上面提到的 --project 来改变他的这个行为。

输入输出指定

如果目录下包含一个默认的 tsconfig.json,那么编译器将会编译目录下所有的文件(包含类型声明文件),我们可以通过下面三种属性来更改这一默认行为:

  1. files 一个列表, 指定所有需要编译的文件,不支持通配符
  2. include 也是一个列表,但是支持三种通配符 *?**/,分别表示任意多个(包含零个)字符,一个任意字符,任意目录包含其子目录
  3. excludeinclude 配置方式一样,同时使用它的时候必须加上 include 属性

他们都是配置文件的顶层属性,注意使用的位置(虽然说现在 JSON scheme 已经很成熟了,但还是了解为好)

如果要查看编译的所有文件,可以使用 --listFiles 编译选项来输出所有被编译的文件

编译选项

TypeScript 工程中的 node_modules/@types 是一个特殊的目录,TypeScript 会将安装在这个目录下的模块的类型文件自动包含到编译中,但是如果我们需要引入一些自定义的类型文件,可以使用 typeRoots 或者 types 编译选项来改变这个行为

  1. typeRoots 编译选项可以指定一个列表,指定所有类型文件的根目录,如果指定了这个属性,那么 node_modules/@types 将不会被包含

  2. types 编译选项可以指定一个列表,指定需要包含的类型文件,是在 typeRoots 中继续细化范围,比如有下面的目录结构

    plaintext
    src/
      index.ts
    node_modules/
      @types/
        lodash/
          index.d.ts
        jquery/
          index.d.ts

    我们可以在 tsconfig.json 中指定

    json
    {
      "compilerOptions": {
        "types": ["lodash"]
      }
    }

    来只包含 lodash 的类型文件


target 上面我们提到过,只是说他会决定编译产物的版本,但也会决定能否使用某些方法。比如我们指定了 targetES6,那么我们就无法使用 ES2017 中支持的 padStart 方法,强行使用会爆出错误(这是否也可以体现出 TypeScript 实际上只是完成了编译的任务,没有做 Polyfill 的工作呢)

但如果指定了 lib 这个字段,使其包含 ES2017.String,那么就可以正常通过编译,虽然此时 target 已经形同虚设了……因为你的编译产物已经包含了一个 ES6 平台无法执行的函数。


outDir 指定了所有输出产物(包含 JavaScript 文件和类型声明文件)的输出位置,通常和 package.json 中的 maintypes 字段综合使用,指定我们编写的工具模块的类型声明文件和入口文件路径。

如果希望最后输出一个文件,那么可以指定 outFile 字段, 但是该字段需要配合 module 使用,module 用来指定编译产物使用的模块语法,可选的有 CommonJSAMD 等,且只有后者才能输出单文件。


除此之外还有很多的编译选项,比如针对 JavaScript 的类型检查编译等,我们后续补充

继承配置

在大型项目中,我们可能需要针对源码,测试等不同部分分别进行编译,而他们可能有共同的配置,为了提高维护性,可以使用 extends 字段来实现配置文件的继承。他有两种解析模式

  1. 相对路径解析:以相对该配置文件的路径来查找(而不是我们运行 tsc 指令时候的相对路径,因为想也知道不可能,如果换个路径编译就无法成功也太荒谬了)
  2. 绝对路径解析:这里的绝对路径不是文件系统绝对路径,而是 node_modules 的绝对路径,比如 "extends": "tsconfig/tsconfig.standard.json" 实际查找的位置为 app/node_modules/tsconfig/tsconfig.standard.json,还有全局的 node_modules 下的绝对路径

三斜线指令

三斜线指令是一类指令,是 TypeScript 早期版本支持的编译指令,现在已经不推荐使用了,更多的推荐在 tsconfig.json 中指定编译选项。

三斜线指令是以 /// 开头的注释,后面跟上一个 XML 标签,比如 reference 等,同时三斜线指令必须在文件的最开始,否则会被作为普通注释对待

/// <reference path="..." />

这个指令用来声明源文件之间的依赖关系,编译一个带有该指令的文件时,编译器会顺带把引用的文件也添加到编译列表,如果使用了前面的 outFile 编译选项,这个指令还可以用作代码排序的手段:

typescript
const a = "lib1";
typescript
const b = "lib2";
typescript
/// <reference path="lib2.ts" />
/// <reference path="lib1.ts" />

const index = "index";
typescript
{
  "compilerOptions": {
    "outFile": "dist/index.js"
  }
}

这样最后输出的 dist/index.js 文件中类似下面

javascript
var b = "lib2";
var a = "lib1";
var index = "index";

如果想要忽略引用文件的三斜线指令,可以使用 --noResolve 编译选项

/// <reference types="..." />

这个指令用来定义对某个类型文件的依赖,比如我们想要使用 jquery 的类型文件,可以使用下面的指令

typescript
/// <reference types="jquery" />

declare var settings: JQuery.AjaxSettings;

需要注意的是这个指令只应该在类型声明文件中使用,在普通的源文件中应该使用 typeRootstypes 编译选项

/// <reference lib="..." />

用来指定对语言内置的某个声明文件的依赖,他和编译选项中的 target 是一样的,因此不推荐使用这个指令