TypeScript tsconfig.json Usage
在TypeScript
项目中,tsconfig.json
文件指定了用来编译这个项目的根文件和编译选项,通过自定义tsconfig.json
文件中的配置项,可以达到我们想要的编译结果。
tsc
当我们使用tsc
命令对项目进行编译时,编译器会从当前目录开始去查找tsconfig.json
文件,逐级向上搜索父目录。
下面我们将通过以下三个方面来讲述tsconfig.json
配置:
- 文件选项:
files
、include
、exclude
- 编译选项:
compilerOptions
- 项目引用:
extends
、references
文件选项
files
files
指定一个包含相对或绝对文件路径的列表,列举在files
中的所有文件,编译器在编译时都会将它们包含在内。
// tsconfig.json
"files": [
"src/core.ts",
"src/index.ts",
]
当配置文件中的files
字段值如上所示时,使用tsc
命令编译时,src
目录下的core.ts
和index.ts
文件会被编译为core.js
和index.js
文件。
include
include
指定编译的文件或目录,include
是支持使用通配符来匹配路径名,支持的通配符及其功能如下表所示:
通配符 | 功能 |
---|---|
* | 匹配0 或多个字符,但是不匹配"."开头的隐藏文件和目录分隔符(/ or \ ) |
? | 匹配一个任意字符,但是不匹配目录分隔符 |
** | 匹配0 或多个字符,包括斜杠(这意味着可以匹配多个目录) |
例如,编译src
下所有文件:
"include": [
"src",
]
只编译src
二级目录下的文件:
"include": [
"src/*/*",
]
当tsconfig.json
文件同时配置了files
和 include
字段时,编译器会将它们进行合并。当files
和 include
中配置的的文件所引用的文件不在其中时,被引用的文件也会被包含进来。
exclude
exclude
指定编译时排除的文件或目录,exclude
的用法与include
相同。
当没有配置files
和 include
字段时,编译器会默认编译当前目录和子目录下所有的ts
文件(.ts
, .d.ts
和 .tsx
),排除在exclude
里配置的文件。而当设置了files
和 include
字段时,可以通过exclude
字段过滤include
的文件。
需要注意的是:通过 files
属性明确指定的文件却总是会被编译,不管exclude
如何配置。
此外,exclude
默认情况下会排除node_modules
,bower_components
,jspm_packages
和输出目录。
compilerOptions
compilerOptions
(编译选项)是tsconfig.json
文件中的重要组成部分,通过配置compilerOptions
中的属性可以实现项目的定制化编译。当tsconfig.json
文件中不包含compilerOptions
对象时,编译器编译时会使用默认值。
本文将compilerOptions
中的属性划分为以下四类进行讲解:
Basic Options
incremental
incremental
增量编译,默认值为true
,作用是加快编译速度。
当该配置为 true
时,会保存 ts
最后一次编译的信息,信息保存在根目录下的 .tsbuildinfo
文件中。下一次编译时,编译器会根据 .tsbuildinfo
文件中的信息判断出编译的最小代价。
与incremental
相关的字段为tsBuildInfoFile
,通过该字段可以指定编译信息保存在自定义的文件。
{
"compilerOptions": {
"incremental": true, /* Enable incremental compilation */
"tsBuildInfoFile": "./buildcache/front-end" /* Specify file to store incremental compilation information */
}
}
target
target
编译后目标语言的版本,默认值为ES3
(不区分大小写)。除了设置为ES3
外,还可以设置为ES5
, ES2015
,......, ES2020
, or ESNEXT
。其中ESNEXT
总是指向最新的js
版本,随着版本更新的变化而变化。但是通常我们都将其设置为ES5
。
{
"compilerOptions": {
"target": "es5"
}
}
module
module
是指生成代码的模块标准,当target
的值为es6
时,module
的默认值为es6
,否则默认为commonjs
。其中es6
是js
模块化规范,commonjs
是node.js
的模块化规范。除了默认的这两个之外,它的值还可以是 'amd', 'umd'等。关于模块化的内容推荐学习 javaScript:模块机制。
下面我们通过一个ts
文件,列举了不同module
值编译后的结果:
ts
文件代码(ES6 规范):
const sum = (a: number, b: number) => a + b;
export default sum;
module: es6
const sum = (a, b) => a + b;
export default sum;
module: commonjs
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const sum = (a, b) => a + b;
exports.default = sum;
module: umd
(function (factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
} else if (typeof define === 'function' && define.amd) {
define(['require', 'exports'], factory);
}
})(function (require, exports) {
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const sum = (a, b) => a + b;
exports.default = sum;
});
amd
不经常使用,但可以结合outFile
字段,将多个相互依赖的文件生成一个文件。
{
"compilerOptions": {
"module": "amd",
"outFile": "./app.js"
}
}
当执行tsc
命令时,会将本目录下的文件一起整合到./app.js
中。
lib
lib
是指TS
编译需要引用的库。当target
设置为较低版本JS
,却在代码中使用更高版本的API
时,代码编 译会出错。
例如 index.ts 的内容为:
let myname: string | undefined = ['robbie', 'peter'].find(item => item === 'robbie');
使用tsc index.js --target es5
编译时会编译失败。
error TS2339: Property 'find' does not exist on type 'string[]'.
此时如果使用tsc index.js --target es5 --lib es6
运行,代码将编译成功。
原因:虽然TS
是JS
的超集,但是仅仅是相对于JS
的语法来说。对于JS
各类型的API
需要引用类库(lib)来支持。所以当代码中使用了JS
较高版本的API
时,最好在lib
字段上添加相应版本。
建议配置:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom","dom.iterable","esnext"],
}
}
outDir
outDir
表示编译后的输出目录。
"outDir": './dist'
当将outDir
设置为./dist
后,编译后的文件将输出到./dist
目录下。
rootDir
rootDir
通过设置输入文件的目录控制输出文件的目录结构,默认输入文件目录为当前目录。
当compilerOptions
的配置如下时:
{
"compilerOptions": {
"outDir": './dist',
"rootDir": './src'
}
}
编译后的目录结构:
|-- dist <========= 输出目录
|-- src
|-- ex1.js
|-- index.js
|-- src
|-- ex1.ts
|-- index.ts
由编译目录可以看到,index.ts
文件虽然不在src
下,但是依旧被编译了,但是执行会打印错误提示信息,建议将所有文件包含在rootDir
下。
error TS6059: File 'D:/Code/ts/index.ts' is not under 'rootDir' 'D:/Code/ts/src'. 'rootDir' is expected to contain all source files.
如果将index.ts
文件放入src
文件下再编译,文件目录如下:
|-- dist <========= 输出目录
|-- ex1.js
|-- index.js
|-- src
|-- ex1.ts
|-- index.ts
可以看出dist
文件下的目录发生了改变,文件中没有包含src
。
allowJs
allowJs
默认值为false
, 当设置它的值为true
时,编译时允许编译 JS
文件。
allowJs: false
|-- dist
|-- ex1.js
|-- src
|-- ex1.ts
|-- ex2.js <= allowJs: false 时 js 文件不编译
allowJs: true
|-- dist
|-- ex1.js
|-- ex2.js <= allowJs: true 时 js 文件也编译了
|-- src
|-- ex1.ts
|-- ex2.js
将 js
工程升级为 ts
工程时,在将所有 js
结尾的文件改成 ts
结尾的同时要注意 ts
文件引用 js
文件的情形。此时引用的 js
文件也需要编译导出。
checkJs
checkJs
默认值为false
,当值为true
时允许在js
文件中进行类型检查和报错。但checkJs
需要配合allowJs
一起使用,当allowJs
为false
时,checkJs
即使为true
也不会起作用。
例如当没有配置outDir
且allowJs
的值为true
时,编译器会编译js
文件,编译后的 js
文件会覆盖源文件,此时如果checkJs
的值为true
时,编译时会报错。
{
"compilerOptions": {
// "outDir": './dist',
"allowJs": true,
"checkJs": true
}
}
jsx
当使用ts
开发时,通常都是以.ts
为后缀。但是当我们开发react
的时候,react
组件一般会以.tsx
作为文件的后缀,此时便需要对jsx
属性进行配置。
jsx
属性有三个值:
jsx 值 | 输入 | 输出 | 输出文件扩展名 |
---|---|---|---|
preserve | <div /> | <div /> | .jsx |
react | <div /> | React.createElement("div") | .js |
react-native | <div /> | <div /> | .js |
declaration
declaration
为true
时,编译后会为每个 ts
文件生成对应的声明文件(.d.ts
文件) 。
原目录:
|-- src
|-- index.ts
编译后目录:
|-- dist
|-- index.js
|-- index.d.ts <= 自动生成的类型声明文件
|-- src
|-- index.ts
声明文件默认会和编译后的js
文件保存在同一目录,但是我们可以在compilerOptions
中配置declarationDir
属性指定声明文件的输出目录。
当我们只想编译生成.d.ts
文件而不想编译生成js
文件时,可以在compilerOptions
中配置 emitDeclarationOnly
为true
。
在项目中使用工程引用时,必须在根 tsconfig.json
中配置declaration
。
sourceMap
sourceMap
为true
时,ts
编译时会生成对应的.js.map
文件。 .js.map
文件是一个信息文件,里面储存着位置信息,记录着编译文件前后的位置关系。当编译后的js
文件出错时,可以更方便的定位到ts
文件的错误位置。
原目录:
|-- src
|-- index.ts
编译后目录:
|-- dist
|-- index.js
|-- index.js.map <= 编译后生成对应的 *.js.map 文件
|-- src
|-- index.ts
declarationMap
与souceMap
类似,declarationMap
会为声明文件生成对应的.d.ts.map
文件。
removeComments
removeComments
的值为true
时,编译后的js
文件会删除源文件中的注释。
noEmit
noEmit
为 true
时,使用 tsc
编译后不会输出文件。
与之相关的属性有noEmitOnError
,noEmitOnError
为true
时,在编译发生错误时不会输出文件。
importHelpers
当ts
中使用类继承等操作时,编译后的js
文件需要用到一些公共方法(helper),每个文件中用到都重新定义一遍是很浪费且很占用空间的。所以当我们配置importHelpers
为true
时,编译后的文件将不再生成helper
函数。
例如当index.ts
文件内容如下时:
class A {}
class B extends A {}
export = B
编译后 helper 函数为:
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 __());
};
})();
配置importHelpers
为true
后,编译后的代码会引用tslib
包,tslib
包中包含__extends
方法。
var tslib_1 = require("tslib");
...
var B =(function (_super){
tslib_1.__extends(B,_super); <=== tslib_1中包含__extends方法
...
}(A))
downlevelIteration
当 target 为 es5 或 es3 时,downlevelIteration
为true
会降级实现遍历器。
例如index.ts
文件为:
let a: number[] = [1, 2, 3];
for (let item of a) {
console.log(item);
}
当不配置downlevelIteration
时,编译结果:
var a = [1, 2, 3];
for (var _i = 0, a_1 = a; _i < a_1.length; _i++) {
var item = a_1[_i];
console.log(item);
}
当downlevelIteration
为true
时,编译结果使用了helper
函数降级实现。
'use strict';
var __values =
(this && this.__values) ||
function (o) {
var s = typeof Symbol === 'function' && Symbol.iterator,
m = s && o[s],
i = 0;
if (m) return m.call(o);
if (o && typeof o.length === 'number')
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
},
};
throw new TypeError(s ? 'Object is not iterable.' : 'Symbol.iterator is not defined.');
};
var e_1, _a;
var a = [1, 2, 3];
try {
for (var a_1 = __values(a), a_1_1 = a_1.next(); !a_1_1.done; a_1_1 = a_1.next()) {
var item = a_1_1.value;
console.log(item);
}
} catch (e_1_1) {
e_1 = { error: e_1_1 };
} finally {
try {
if (a_1_1 && !a_1_1.done && (_a = a_1.return)) _a.call(a_1);
} finally {
if (e_1) throw e_1.error;
}
}
isolatedModules
在typescript
中,默认情况下却将所有的 *.ts
文件作用域放到了一起。所以即使不同文件有同名变量也会报错。此时可以将isolatedModules
设为true
,这样就可以隔离各个文件的作用域。
|-- src
|-- index.ts
|-- exp1.ts
例如在src
目录下的index.ts
和exp1.ts
文件中都定义了一个变量test
,此时编译器会提示错误:Cannot redeclare block-scoped variable test
。
除了使用isolatedModules
字段外,还可以使用export { test }
或者export defalut test
,让ts
文件成为一个模块,这样也可以达到隔离作用域的效果。
Strict Type-Checking Options
与严格类型检查相关的配置项一共有以下八项:
// "strict": true, // 开启所有严格的类型检查
// "noImplicitAny": false, // 不允许隐式的 any 类型
// "strictNullChecks": false, // 不允许把 null、undefined 赋值给其他类型变量
// "strictFunctionTypes": false // 不允许函数参数双向协变
// "strictPropertyInitialization": false, // 类的实例属性必须初始化
// "strictBindCallApply": false, // 严格的 bind/call/apply 检查(参数类型相同)
// "noImplicitThis": false, // 不允许 this 有隐式的 any 类型,避免this指向全局
// "alwaysStrict": false, // 在代码中注入 "use strict";
strict
strict
的默认值为false
,当strict
配置为true
时,其它七项默认为开启状态,当配置为false
时,其它七项默认为关闭状态,也就是说其它七项是strict
的子集。
当strict
为false
时,可以根据自己的需求,通过设置其它几项自定义类型检查。
noImplicitAny
当noImplicitAny
的值为true
时,ts
文件中所有的函数参数都必须明确参数类型,否则会编译出错。
function echo(o) {
// <= 编译报错:Parameter 'o' implicitly has an 'any' type.
console.log(o);
}
strictNullChecks
当strictNullChecks
的值为true
时,ts
文件中不能将null
、undefined
赋值给其他类型变量。当赋值给其它类型时会编译出错。
strictFunctionTypes
当strictFunctionTypes
的值为true
时,ts
文件不允许函数参数双向协变 。
strictBindCallApply
当strictBindCallApply
的值为true
时对 bind
、call
、apply
进行更加严格的类型检查,要求参数类型和个数必须保持一致。
例如当传递的参数少于函数参数,或参数类型不对时,编译时就会报错,如下例所示:
function foo(a: number, b: string): string {
return a + b;
}
let a = foo.call(undefined, 10); // <=== Expected 3 arguments, but got 2
let b = foo.call(undefined, 10, 2); // <=== Argument of type '2' is not assignable to parameter of type 'string'
strictPropertyInitialization
当strictPropertyInitialization
的值为true
时,类的实例属性必须初始化。即类中每个实例属性都有初始值,初始值可以在 constructor
中设置,也可以在声明时设置。
未赋值:
class C {
name: string; // <= Property 'name' has no initializer and is not definitely assigned in the constructor.
}
赋值:
class C {
name: string = 'dk'; // <=== 在声明变量时初始化值
age: number;
constructor(age: number) {
this.age = age; // <=== 在构造函数中赋值
}
}
noImplicitThis
当noImplicitThis
的值为true
时,不允许 this
有隐式的 any
类型,避免this
指向全局。
class Age {
age: number = 10;
getAge() {
return function () {
console.log(this.age);
};
}
}
let age = new Age().getAge();
age();
由上例可知this
并不指向Age
类,而是指向undefined
,此时如果noImplicitThis
的值为true
,将会编译出错。
alwaysStrict
alwaysStrict
为 true 时,编译后的代码会在文件开头加上"use strict"
。
Additional Checks
noUnusedLocals
noUnusedLocals
的值为true
时,ts
文件不允许出现只声明未使用 的局部变量。
noUnusedParameters
noUnusedParameters
的值为true
时,函数中的参数必须在函数中被使用。
由下例可知,参数c
在函数参数中被声明,但是并未使用,编译出错
function sum(a: number, b: number, c: number) {
// <= 编译报错:'c' is declared but its value is never read.
return a + b;
}
noImplicitReturns
noImplicitReturns
的值为true
时,所有的分支必须有返回值。
function fn(a: number) {
if (a > 0) {
return false;
} else {
a = -a; // <= 编译报错:Not all code paths return a value.
}
}
由上例可知,else
分支没有返回值,此时只要加上return
语句便可编译通过。
noFallthroughCasesInSwitch
noFallthroughCasesInSwitch
的值为true
时,可以防止switch
语句贯穿(当没有break
的时候会一直向下执行)。当break
丢失时,会编译报错:Fallthrough case in switch。
Module Resolution Options
moduleResolution
moduleResolution
表示模块解析策略,它的默认值为node
,除了使用node
对模块进行解析外,还可以使用classic
(TypeScript pre-1.6)。
class
模块的解析规则:
![D3twOQ](https://cosmos-x.oss-cn-hangzhou.aliyuncs.com/微信截图_20200229145914.png)
node
模块的解析规则:
![D3twOQ](https://cosmos-x.oss-cn-hangzhou.aliyuncs.com/微信截图_20200229145940.png)
baseUrl
baseUrl
解析非相对导入模块的基地址,默认为当前目录。
paths
paths
是指相对于baseUrl
的路径映射,paths
依赖于baseUrl
而存在。
比如,当index.ts
想导入Jquery
的精简版本,而不是默认版本。可以设置path
为:
"baseUrl": "./",
"paths": {
"jquery": ["node_modules/jquery/dist/jquery.slim.min.js"]
}
目录结构:
|-- node_modules
|-- index.ts
rootDirs
rootDirs
功能是将多个目录放在一个虚拟目录下。
|-- dist
|--util.d.ts
|--util.js
|-- src
|-- index.ts
util
这个类库会一直在输出目录,不会再次被构建。而当src
文件下的index.js
引用util
时,需要使用以下方式 :
import { util } from '../dist/util';
但当src
被构建进输出目录后,之前导入类库的路径就会出错。此时可以使用 rootDirs
将dist
和src
放在同一个虚拟目录,如下所示:
"rootDirs": ['src', 'dist']
此时util.*
和index.ts
可以看作在同一目录下,所以将引用改为:
import { util } from './util';
typeRoots
typeRoots
指的是声明文件的目录,默认node_modules/@types
。
当我们使用npm
安装了node
包后,发现引用fs
模块依旧出错,这是因为 typescript
不认识 nodejs
原生api
,需要安装对应的声明文件 @types/node
。与node
相似,当我们安装包后,引用依旧出错,可以看一下是否安装了它的声明文件。
types
types
为声明文件包,当我们将包名放到types
属性中时,只会从types
的属性值中进行查找。
例如配置为:
{
"compilerOptions": {
"types" : ["node", "lodash"]
}
}
编译时只会找 ./node_modules/@types/node
, ./node_modules/@types/lodash
两个包的声明文件,其它包的声明文件不会查找。
esModuleInterop
esModuleInterop
的默认值为false
,当esModuleInterop
的值为true
时,允许模块使用export = 模块名
导出,由import XX from "模块名"
导入。
例如在react
项目中,我们项目中会使用import React from 'react';
,因此我们需要将esModuleInterop
的值设为true
。否则,只能使用import * as React from 'react'
来引入react
allowUmdGlobalAccess
allowUmdGlobalAccess
的值为true
时,允许以全局变量的形式访问 UMD
模块
工程引用
工程引用是TypeScript 3.0
的新特性,它支持将TypeScript
程序的结构分割成更小的组成部分,并可以配置这些小的部分产生依赖关系。这样可以改善构建时间,强制在逻辑上对组件进行分离,更好地组织你的代码。
TypeScript 3.0
还 引入了tsc
的一种新模式,即--build
(简写为-b
)标记,它与工程引用协同工作可以加速TypeScript
的构建。使用方式:
tsc -b 文件路径
工程引用前
工程引用出现前,因为所有的配置都是在同一个文件tsconfig
中,配置起来顾此失彼,略显笨重。可以看一下下面这个目录结构:
├── src
│ ├── client
│ │ ├── index.ts
│ ├── common
│ │ ├── index.ts
│ ├── server
│ │ ├── index.ts
├── test
│ ├── client.spec.ts
│ ├── server.spec.ts
├── package.json
├── tsconfig.json
可以将该项目的看作一个前后端未分离的项目,client
下是客户端代码,server
下是服务器代码 ,common
是两者共用的文件,其中client/index.ts
和 server/index.ts
会引用common/index.ts
的代码。test
中存放的是client
和server
的单元测试代码。
tsconfig.json
的配置如下:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
"outDir": "./dist"
}
}
项目编译后 的dist
目录如下:
├── dist
│ ├── src
│ │ ├── client
│ │ ├── common
│ │ ├── server
│ ├── test
通过上面的内容可以看出,在没有引入工程引用前存在以下几个缺点:
-
希望
src
下面的文件直接被编译到dist
目录下, 但由于需要编译test
文件而达不到这样的效果。 -
我们无法单独构建
client
端, 或者server
端的代码,构建体积较大 。 -
我们不希望把
test
构建到dist
目录下。 -
一个文件发生改动,要编译所有文件,构建比较耗时。
虽然1
可以通过配置include
字段实现只将src
下的文件编译到dist
,同时也满足了3
,但是这样test
不能一起编译会显得很麻烦。此时我们可以通过使用工程引用,单独编译各个模块。
使用工程引用
为了优化构建过程,我们可以使用工程引用,将之前的目录改造如下:
├── src
│ ├── client
│ │ ├── index.ts
│ │ ├── tsconfig.json
│ ├── common
│ │ ├── index.ts
│ │ ├── tsconfig.json
│ ├── server
│ │ ├── index.ts
│ │ ├── tsconfig.json
├── test
│ ├── client.spec.ts
│ ├── server.spec.ts
│ ├── tsconfig.json
├── package.json
├── tsconfig.json
通过目录结构可以看出,我们为每个目录都添加了tsconfig.json
来满足各个模块的编译需求。
根 tsconfig.json
文件配置如下:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
// "outDir": "./dist" 关闭 outDir 选项, 即不在根配置中指定输入目录
"composite": true, // 使用 composite, 它意味着工程可以被引用, 可以帮助ts编译器快速定位工程文件的输出文件
"declaration": true // 使用 composite 选项必须开启 declaration
}
}
使用工程引用时,client/tsconfig.json
的配置:
{
"extends": "../../tsconfig.json", // 导入根配置文件
"compilerOptions": {
"outDir": "../../dist/client" // 指定输出目录
},
"references": [{ "path": "../common" }] // 因为 client 引用了 common, 故需要将 common 引入进来
}
其中extends
用来导入根配置文件。而references
导入引用工程中的模块实际加载的是它输出的声明文件(.d.ts
),这也是在根配置文件中必须配置"composite": true
和"declaration": true
的原因。
在使用tsc -b src/client
进行编译时,它所依赖的common
也会被编译到dist
文件,其目录结构如下所示:
├─dist
│ ├─client
│ │ index.d.ts
│ │ index.js
│ │ tsconfig.tsbuildinfo
│ │
│ └─common
│ index.d.ts
│ index.js
│ tsconfig.tsbuildinfo
server/tsconfig.json
的配置与client/tsconfig.json
类似,只需要将outDir
改动以下即可。当server
编译时,由于common
文件已经被编译过了,所以此时不会对其再次编译,这样也节省了编译的时间。
common/tsconfig.json
的配置:
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/common"
}
}
test/tsconfig.json
的配置:
{
"extends": "../tsconfig.json", // 导入根配置文件
"references": [{ "path": "../src/client" }, { "path": "../src/server" }] // 引用工程文件
}
tsc -b 命令行
上面也提到,使用tsc -b
可以对ts
文件进行编译。
> tsc -b # Build the tsconfig.json in the current directory
> tsc -b src # Build src/tsconfig.json
> tsc -b foo/release.tsconfig.json bar # Build foo/release.tsconfig.json and bar/tsconfig.json
tsc -b
还支持其它一些选项:
- --verbose:打印详细的日志(可以与其它标记一起使用)
- --dry: 显示将要执行的操作但是并不真正进行这些操作
- --clean: 删除指定工程的输出(可以与--dry 一起使用)
- --force: 把所有工程当作非最新版本对待
- --watch: 观察模式(可以与--verbose 一起使用)
--verbose
对于前面提到的项目,在编译client
和server
时就可以添加--verbose
参数,打印编译日志。具体过程如下所示:
tsc -b ./src/client --verbose
build client 日志:
[11:49:51] Project 'src/common/tsconfig.json' is out of date because output file 'dist/common/index.js' does not exist
[11:49:51] Building project 'D:/Code/ts/src/new/src/common/tsconfig.json'...
[11:49:56] Project 'src/client/tsconfig.json' is out of date because output file 'dist/client/index.js' does not exist
[11:49:56] Building project 'D:/Code/ts/src/new/src/client/tsconfig.json'...
tsc -b ./src/server --verbose
build server 日志:
[11:50:09] Project 'src/common/tsconfig.json' is up to date because newest input 'src/common/index.ts' is older than oldest output 'dist/common/index.js'
[11:50:09] Project 'src/server/tsconfig.json' is out of date because output file 'dist/server/index.js' does not exist
[11:50:09] Building project 'D:/Code/ts/src/new/src/server/tsconfig.json'...
通过打印的日志可以看出common
只编译了一次,不会被重复编译。
--dry
当server
未编译时,执行 tsc -b ./src/server --verbose --dry
时的输出日志如下所示:
[12:52:45] Project 'src/common/tsconfig.json' is up to date because newest input 'src/common/index.ts' is older than oldest output 'dist/common/index.js'
[12:52:45] Project 'D:/Code/ts/src/new/src/common/tsconfig.json' is up to date
[12:52:45] Project 'src/server/tsconfig.json' is out of date because output file 'dist/server/index.js' does not exist
[12:52:45] A non-dry build would build project 'D:/Code/ts/src/new/src/server/tsconfig.json'
当server
编译后,再次执行 tsc -b ./src/server --verbose --dry
时的输出日志如下所示:
[12:55:24] Project 'src/common/tsconfig.json' is up to date because newest input 'src/common/index.ts' is older than oldest output 'dist/common/index.js'
[12:55:24] Project 'D:/Code/ts/src/new/src/common/tsconfig.json' is up to date
[12:55:24] Project 'src/server/tsconfig.json' is up to date because newest input 'src/server/index.ts' is older than oldest output 'dist/server/index.js'
[12:55:24] Project 'D:/Code/ts/src/new/src/server/tsconfig.json' is up to date
通过上面的日志可以看出,当使用--dry
参数时会检测将要执行的操作,但并不会真正的执行。
--clean
使用--clean
参数时会删除指定工程的输出。例如:
tsc -b ./src/server --dry --clean
A non-dry build would delete the following files:
* D:/Code/ts/src/new/dist/common/index.js
* D:/Code/ts/src/new/dist/common/index.d.ts
* D:/Code/ts/src/new/dist/common/tsconfig.tsbuildinfo
* D:/Code/ts/src/new/dist/server/index.js
* D:/Code/ts/src/new/dist/server/index.d.ts
* D:/Code/ts/src/new/dist/server/tsconfig.tsbuildinfo
由输出结果可以看出,通过添加--clean
,清除已经编译好的文件,即tsc -b ./src/server --clean
是tsc -b ./src/server
的逆操作。
--force
如果想刷新已经编译好的文件,可以使用 --force
参数。下面对已编译过的server
为例:
tsc -b ./src/server --verbose
[12:24:44] Project 'src/common/tsconfig.json' is up to date because newest input 'src/common/index.ts' is older than oldest output 'dist/common/index.js'
[12:24:44] Project 'src/server/tsconfig.json' is up to date because newest input 'src/server/index.ts' is older than oldest output 'dist/server/index.js'
tsc -b ./src/server --verbose --force
[12:19:51] Project 'src/common/tsconfig.json' is up to date because newest input 'src/common/index.ts' is older than oldest output 'dist/common/index.js'
[12:19:51] Building project 'D:/Code/ts/src/new/src/common/tsconfig.json'...
[12:19:57] Project 'src/server/tsconfig.json' is up to date with .d.ts files from its dependencies
[12:19:57] Building project 'D:/Code/ts/src/new/src/server/tsconfig.json'...
--watch
当使用--watch
参数时会开启观察编译模式,当检测到被观察的文件出现修改后,将启动增量编译。
tsc -b ./src/server --verbose --watch
[12:28:50] Starting compilation in watch mode...
[12:28:50] Project 'src/common/tsconfig.json' is up to date because newest input 'src/common/index.ts' is older than oldest output 'dist/common/index.js'
[12:28:50] Project 'src/server/tsconfig.json' is up to date because newest input 'src/server/index.ts' is older than oldest output 'dist/server/index.js'
[12:28:50] Found 0 errors. Watching for file changes.
- 修改
server/index.ts
文件后:
[12:30:55] File change detected. Starting incremental compilation...
[12:30:55] Project 'src/server/tsconfig.json' is out of date because oldest output 'dist/server/index.js' is older than newest input 'src/server/index.ts'
[12:30:55] Building project 'D:/Code/ts/src/new/src/server/tsconfig.json'...
[12:30:57] Found 0 errors. Watching for file changes.
由修改后打印的日志可以看出,文件修改后会对修改的文件进行增量编译,然后继续观察文件。
参考目录
- 配置 tsconfig.json:文件选项,by 梁宵
- 配置 tsconfig.json:编译选项,by 梁宵
- tsconfig.json 详解一,by dkvirus
- TypeScript Deep Dive,by Basarat
- TypeScript official docs: Compiler Options
- TypeScript official docs: tsconfig.json
- 配置 tsconfig.json:工程引用,by 梁宵
- 聊一聊 TypeScript 的工程引用, by YanceyOfficial
- TypeScript official docs: Project References