本篇主要介绍 tsconfig.json 中与编译相关的选项。
{
"compilerOptions": {
"incremental": true, // 增量编译
"tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
"diagnostics": true, // 打印编译信息
"target": "es5", // 目标语言的版本
"module": "commonjs", // 生成代码的模块标准
"outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在 AMD 模块中
"lib": [], // TS 需要引用的库,即声明文件,es5 默认 "dom", "es5", "scripthost"
"allowJs": true, // 允许编译 JS 文件(js、jsx)
"checkJs": true, // 允许在 JS 文件中报错,通常与 allowJS 一起使用
"outDir": "./out", // 指定输出目录
"rootDir": "./", // 指定输入文件目录(用于输出)
"declaration": true, // 生成声明文件
"declarationDir": "./d", // 声明文件的路径
"emitDeclarationOnly": true, // 只生成声明文件
"sourceMap": true, // 生成目标文件的 sourceMap
"inlineSourceMap": true, // 生成目标文件的 inline sourceMap
"declarationMap": true, // 生成声明文件的 sourceMap
"typeRoots": [], // 声明文件目录,默认 node_modules/@types
"types": [], // 声明文件包
"removeComments": true, // 删除注释
"noEmit": true, // 不输出文件
"noEmitOnError": true, // 发生错误时不输出文件
"noEmitHelpers": true, // 不生成 helper 函数,需额外安装 ts-helpers
"importHelpers": true, // 通过 tslib 引入 helper 函数,文件必须是模块
"downlevelIteration": true, // 降级遍历器的实现(es3/5)
"strict": true, // 开启所有严格的类型检查
"alwaysStrict": false, // 在代码中注入 "use strict";
"noImplicitAny": false, // 不允许隐式的 any 类型
"strictNullChecks": false, // 不允许把 null、undefined 赋值给其他类型变量
"strictFunctionTypes": false, // 不允许函数参数双向协变
"strictPropertyInitialization": false, // 类的实例属性必须初始化
"strictBindCallApply": false, // 严格的 bind/call/apply 检查
"noImplicitThis": false, // 不允许 this 有隐式的 any 类型
"noUnusedLocals": true, // 检查只声明,未使用的局部变量
"noUnusedParameters": true, // 检查未使用的函数参数
"noFallthroughCasesInSwitch": true, // 防止 switch 语句贯穿
"noImplicitReturns": true, // 每个分支都要有返回值
"esModuleInterop": true, // 允许 export = 导出,由import from 导入
"allowUmdGlobalAccess": true, // 允许在模块中访问 UMD 全局变量
"moduleResolution": "node", // 模块解析策略
"baseUrl": "./", // 解析非相对模块的基地址
"paths": { // 路径映射,相对于 baseUrl
"jquery": ["node_modules/jquery/dist/jquery.slim.min.js"]
},
"rootDirs": ["src", "util"], // 将多个目录放在一个虚拟目录下,用于运行时
"listEmittedFiles": true, // 打印输出的文件
"listFiles": true, // 打印编译的文件(包括引用的声明文件)
}
}接下来,我们会逐个分析上面的配置项。
它的含义是增量编译,TypeScript 编译器在第一次编译后会生成一个可以编译信息的文件,在之后的编译之后会根据这个文件提高编译的速度。该文件默认会在根目录下名称为 tsconfig.tsbuildinfo:
{
"program": {
"fileInfos": {
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.d.ts": {
"version": "49ff9798f592c8b7e628fd881401e68810c1b3589ecd7a41b32b3c287374cde0",
"signature": "49ff9798f592c8b7e628fd881401e68810c1b3589ecd7a41b32b3c287374cde0"
},
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.es5.d.ts": {
"version": "ff5688d6b2fcfef06842a395d7ff4d5730d45b724d4c48913118c889829052a1",
"signature": "ff5688d6b2fcfef06842a395d7ff4d5730d45b724d4c48913118c889829052a1"
},
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.dom.d.ts": {
"version": "2d53f3741e5a4f78a90f623387d71a1cc809bb258f10cdaec034b67cbf71022f",
"signature": "2d53f3741e5a4f78a90f623387d71a1cc809bb258f10cdaec034b67cbf71022f"
},
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.webworker.importscripts.d.ts": {
"version": "fe4e59403e34c7ff747abe4ff6abbc7718229556d7c1a5b93473fb53156c913b",
"signature": "fe4e59403e34c7ff747abe4ff6abbc7718229556d7c1a5b93473fb53156c913b"
},
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.scripthost.d.ts": {
"version": "b9faa17292f17d2ad75e34fac77dd63a6403af1dba02d39cd0cbb9ffdf3de8b9",
"signature": "b9faa17292f17d2ad75e34fac77dd63a6403af1dba02d39cd0cbb9ffdf3de8b9"
},
"./src/index.ts": {
"version": "a0e2a405f15ab7f6218e22c622acc2706d51eae2aa90f302f81f68628e22cd55",
"signature": "ec8f4696ee1308e5fbc9f50626f5677f0f15bd7c228311cbcc0669233461fa1d"
}
},
"options": {
"incremental": true,
"configFilePath": "./tsconfig.json"
},
"referencedMap": {},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.d.ts",
"./src/index.ts",
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.es5.d.ts",
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.dom.d.ts",
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.webworker.importscripts.d.ts",
"../../../../../usr/local/lib/node_modules/typescript/lib/lib.scripthost.d.ts"
]
},
"version": "3.6.2"
}可以修改增量编译文件的存储文件夹和文件名
打印编译信息。
Files: 6
Lines: 24817
Nodes: 111372
Identifiers: 41045
Symbols: 27914
Types: 8268
Memory used: 68338K
I/O read: 0.01s
I/O write: 0.00s
Parse time: 0.42s
Bind time: 0.23s
Check time: 1.13s
Emit time: 0.02s
Total time: 1.80s设置目标语言的版本,可设置为 ES3、ES5 和 ES2015 等等,默认为 ES3。
设置生成代码的模块标准,可以设置为 CommonJS、AMD 和 UMD 等等。
将多个相互依赖的文件生成一个文件,可以用在 AMD 模块中。
我们创建两个文件,分别为 index.ts 和 amd.ts,如下所示:
// ./src/index.ts
import a = require('./amd')
let str: string = 'abc'// ./src/amd.ts
let amd: number = 0
export = amdindex.ts 引入 amd.ts,我们再设置一下 tsconfig.json 文件。
{
"compilerOptions": {
"module": "amd",
"outFile": "./app.js"
}
}然后在命令行执行 tsc 命令,编译器会将两个 ts 文件合并编译成一个 app.js 文件。
define("amd", ["require", "exports"], function (require, exports) {
"use strict";
var amd = 0;
return amd;
});
define("index", ["require", "exports"], function (require, exports) {
"use strict";
exports.__esModule = true;
var str = 'abc';
});指定 ts 需要引用的库,即声明文件,若 target 设置为 es5 时,lib 默认为 ["dom", "es5", "scripthost"]。
例如,我们想在 ts 中使用 es2019 的方法。可以在 lib 配置里添加 es2019。
允许编译器编译 JS 文件(js、jsx)。
允许在 JS 文件中报错,通常与 allowJS 一起使用。
指定输出目录
指定输入文件目录
编译器编译时,允许生成声明文件(.d.ts)。
指定声明文件的生成的目录。
编译器编译时,只允许生成声明文件。
编译器编译时,生成目标文件的 sourceMap 文件。
编译器编译时,将 sourceMap 生成在 js 文件中。
编译器编译时,生成声明文件的 sourceMap。
设置声明文件目录,默认 node_modules/@types
这是声明文件包,如果设置了某一个声明文件,那么编译器只会加载这个声明文件。
是否删除注释
执行 tsc 不会输出任何文件
发生错误时不输出文件
设置为 true 时,不生成 helper 函数。先看下面示例:
class B {}
class A extends B {}
export = A我们创建了一个模块。然后在控制台执行 tsc,下面就是编译后的结果:
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var B = /** @class */ (function () {
function B() {
}
return B;
}());
var A = /** @class */ (function (_super) {
__extends(A, _super);
function A() {
return _super !== null && _super.apply(this, arguments) || this;
}
return A;
}(B));
module.exports = A;编译器会自动生成 __extends。
如果我们将 noEmitHelpers 这个配置设置为 true 之后。编译后的结果如下:
"use strict";
var B = /** @class */ (function () {
function B() {
}
return B;
}());
var A = /** @class */ (function (_super) {
__extends(A, _super);
function A() {
return _super !== null && _super.apply(this, arguments) || this;
}
return A;
}(B));
module.exports = A;上面的编译后的结果中 __extends 未定义。ts 已经为开发者定义了一个配置项,方便解决该问题。 就是接下来要介绍的配置 importHelpers。
通过 tslib 引入 helper 函数,文件必须是模块。编译结果如下:
"use strict";
var tslib_1 = require("tslib");
var B = /** @class */ (function () {
function B() {
}
return B;
}());
var A = /** @class */ (function (_super) {
tslib_1.__extends(A, _super);
function A() {
return _super !== null && _super.apply(this, arguments) || this;
}
return A;
}(B));
module.exports = A;若提示 tslib 未找到时,可以手动安装它。
降级遍历器的实现,下面是一个 es6 语法:
let a = [1, 2, 3]
let b = [4, ...a]我们打开这项配置,进行编译后结果如下:
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
var a = [1, 2, 3];
var b = __spread([4], a);会生成两个 helper 函数。
表示开启所有严格的类型检查,若 strict 为 true,alwaysStrict、noImplicitAny、strictNullChecks、strictFunctionTypes、strictPropertyInitialization、strictBindCallApply 和 noImplicitThis 选项默认都为 true。
在代码中注入 use strict。
不允许隐式的 any 类型。
不允许把 null、undefined 赋值给其他类型变量。
不允许函数参数双向协变。
类的实例属性必须初始化。
严格的 bind、call、apply 检查。
function add (a: number, b: number) {
return a + b
}
add.call(undefined, 1, '2')
// Error: Argument of type '"2"' is not assignable to parameter of type 'number'.不允许 this 有隐式的 any 类型。
class A {
name: string = 'abc'
getName () {
return function () {
console.log(this.name)
}
}
}
// Error: 'this' implicitly has type 'any' because it does not have a type annotation.检查只声明,未使用的局部变量
检查未使用的函数参数
防止 switch 语句贯穿
每个分支都要有返回值
允许 export = 方式导出,也可以用 import = 的方式导入。
允许在模块中访问 UMD 全局变量
模块解析策略,这里提供两种解析策略 node 和 classic,ts 默认使用 node 解析策略。
- classic 模块解析策略
适用于 AMD、System、ES2015
如果一个模块使用相对方式导入时,ts 就会依次解析同级目录 .ts、.d.ts 文件。
// /root/src/moduleA.ts
import { b } from './moduleB'
/**
* /root/src/moduleB.ts
* /root/src/moduleB.d.ts
*/如果使用非相对方式导入时如下, ts 会从当前目录的 node_modules 目录里查找,如果未找到,会依次向上级目录查找。
// /root/src/moduleA.ts
import { b } from 'moduleB'
/**
* /root/src/node_modules/moduleB.ts
* /root/src/node_modules/moduleB.d.ts
*
* /root/node_modules/moduleB.ts
* /root/node_modules/moduleB.d.ts
*
* /node_modules/moduleB.ts
* /node_modules/moduleB.d.ts
*/- node 模块解析策略
使用相对方式导入
// /root/src/moduleA.ts
import { b } from './moduleB'
/**
* /root/src/moduleB.ts
* /root/src/moduleB.tsx
* /root/src/moduleB.d.ts
* /root/src/moduleB/package.json ( types 属性)
* /root/src/moduleB/index.ts
* /root/src/moduleB/index.tsx
* /root/src/moduleB/index.d.ts
*/使用非相对方式导入
// /root/src/moduleA.ts
import { b } from 'moduleB'
/**
* /root/src/node_modules/moduleB.ts
* /root/src/node_modules/moduleB.tsx
* /root/src/node_modules/moduleB.d.ts
* /root/src/node_modules/package.json ( types 属性)
* /root/src/node_modules/index.ts
* /root/src/node_modules/index.tsx
* /root/src/node_modules/index.d.ts
*
* 依次向上目录查找
*/解析非相对模块的基地址,默认为当前目录
路径映射,相对于 baseUrl。比如示例中我们想引入 jquery 精简版本,可以制定它的相对路径。
将多个目录放在一个虚拟目录下,用于运行时。
比如 我们创建量以下两个文件。
// /util/a.ts
let a: string = 'A'
export = a// /src/index.ts
import a from './a'注意在引入 a 时,是引入的当前目录。因为当 rootDirs 设置了 src 和 util 目录时,编译器默认它们属于同级目录。
打印输出的文件。
打印编译的文件,包括引用的声明文件。