tsconfig.js配置项中文解析(2023.10.25更新)
- Root
- [files, include, exclude](#files, include, exclude "#filesinclude-%E4%B8%8E-exclude")
- extends
- 输出相关选项
- [Env,Language 环境及设置相关选项](#Env,Language 环境及设置相关选项 "#envlanguage-%E7%8E%AF%E5%A2%83%E5%8F%8A%E8%AE%BE%E7%BD%AE%E7%9B%B8%E5%85%B3%E9%80%89%E9%A1%B9")
- [Modules 模块解析相关选项](#Modules 模块解析相关选项 "#modules-%E6%A8%A1%E5%9D%97%E8%A7%A3%E6%9E%90%E7%9B%B8%E5%85%B3%E9%80%89%E9%A1%B9")
- module
- moduleResolution
- moduleSuffixes
- baseUrl
- paths
- noResolve
- customConditions
- resolveJsonModule
- resolvePackageJsonImports
- resolvePackageJsonExports
- allowArbitraryExtensions
- allowImportingTsExtensions
- allowUmdGlobalAccess
- rootDir
- rootDirs
- [types 与 typeRoot](#types 与 typeRoot "#types-%E4%B8%8E-typeroot")
- [typeChecking 类型检查相关选项类型检查相关选项](#typeChecking 类型检查相关选项类型检查相关选项 "#typechecking-%E7%B1%BB%E5%9E%8B%E6%A3%80%E6%9F%A5%E7%9B%B8%E5%85%B3%E9%80%89%E9%A1%B9")
- alwaysStrict
- strict
- strictNullChecks
- strictBindCallApply
- strictFunctionTypes
- noImplicitAny
- noImplicitThis
- strictPropertyInitialization
- useUnknownInCatchVariables
- allowUnreachableCode
- allowUnusedLabels
- exactOptionalPropertyTypes
- noFallthroughCasesInSwitch
- noImplicitOverride
- noImplicitReturns
- noPropertyAccessFromIndexSignature
- noUncheckedIndexedAccess
- noUnusedLocals
- noUnusedParameters
- [JS 相关选项](#JS 相关选项 "#js-%E7%9B%B8%E5%85%B3%E9%80%89%E9%A1%B9")
- [Editor 编辑器相关选项](#Editor 编辑器相关选项 "#editor-%E7%BC%96%E8%BE%91%E5%99%A8%E7%9B%B8%E5%85%B3%E9%80%89%E9%A1%B9")
- [Interop Constraints 互相操作约束(针对 CommonJS 模块)](#Interop Constraints 互相操作约束(针对 CommonJS 模块) "#interop-constraints-%E4%BA%92%E7%9B%B8%E6%93%8D%E4%BD%9C%E7%BA%A6%E6%9D%9F%E9%92%88%E5%AF%B9-commonjs-%E6%A8%A1%E5%9D%97")
- [Backwards Compatibility 向后兼容相关选项](#Backwards Compatibility 向后兼容相关选项 "#backwards-compatibility-%E5%90%91%E5%90%8E%E5%85%BC%E5%AE%B9%E7%9B%B8%E5%85%B3%E9%80%89%E9%A1%B9")
- [charset (deprecated)](#charset (deprecated) "#charset-deprecated")
- [keyofStringsOnly (deprecated)](#keyofStringsOnly (deprecated) "#keyofstringsonly-deprecated")
- [noImplicitUseStrict (deprecated)](#noImplicitUseStrict (deprecated) "#noimplicitusestrict-deprecated")
- [noStrictGenericChecks (deprecated)](#noStrictGenericChecks (deprecated) "#nostrictgenericchecks-deprecated")
- out
- [suppressExcessPropertyErrors (deprecated)](#suppressExcessPropertyErrors (deprecated) "#suppressexcesspropertyerrors-deprecated")
- [suppressImplicitAnyIndexErrors (deprecated)](#suppressImplicitAnyIndexErrors (deprecated) "#suppressimplicitanyindexerrors-deprecated")
- [extendedDiagnostics 编译分析相关选项](#extendedDiagnostics 编译分析相关选项 "#extendeddiagnostics-%E7%BC%96%E8%AF%91%E5%88%86%E6%9E%90%E7%9B%B8%E5%85%B3%E9%80%89%E9%A1%B9")
- [Output Formatting 输出相格式化关选项](#Output Formatting 输出相格式化关选项 "#output-formatting-%E8%BE%93%E5%87%BA%E7%9B%B8%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%85%B3%E9%80%89%E9%A1%B9")
- [Completeness 完整性配置选项](#Completeness 完整性配置选项 "#completeness-%E5%AE%8C%E6%95%B4%E6%80%A7%E9%85%8D%E7%BD%AE%E9%80%89%E9%A1%B9")
- [Watch Options 监视模式相关选项](#Watch Options 监视模式相关选项 "#watch-options-%E7%9B%91%E8%A7%86%E6%A8%A1%E5%BC%8F%E7%9B%B8%E5%85%B3%E9%80%89%E9%A1%B9")
Root 输入相关选项
files、include 与 exclude
指定哪些文件需要被 ts 处理, 当这些需要被 ts 处理的文件较少时, 可以考虑使用files
字段, 如果需要被处理的文件比较多, 可以考虑使用include
和exclude
json
{
"compilerOptions": {},
"files": [
"core.ts",
"sys.ts",
"types.ts",
"scanner.ts",
"parser.ts",
"utilities.ts",
"binder.ts",
"checker.ts",
"tsc.ts"
]
}
include
以 glob
(不懂的可以百度) 的方式指定哪些文件需要被 ts 处理
json
{
"include": ["src/**/*", "tests/**/*"]
}
exclude
以glob
的方式, 从include
指定的文件中排除一些文件, 这些被排除的文件不会被 ts 处理
json
{
"exclude": ["src/**/*", "tests/**/*"]
}
需要注意的是:
exclude
只会排除include
范围中指定的文件, 如果某个文件在exclude
的范围内, 但是该文件被include
范围内的某个文件引用, 或者这个文件被声明在files
中, 该文件依然会被 ts 处理
extends
extends
属性是 TypeScript 配置文件 tsconfig.json 中的一个配置项,用于指定一个基础配置文件,以继承其配置选项。这个基础配置文件可以是另一个 tsconfig.json 文件,允许在多个 TypeScript 项目中共享通用的配置,从而避免重复配置。
继承的配置文件:extends 属性的值应该是一个包含所需配置选项的有效 tsconfig.json 文件的相对或绝对路径。这个文件可以是项目内的另一个配置文件,也可以是外部的共享配置文件。
合并配置:当使用 extends 属性时,TypeScript 将合并基础配置文件和当前配置文件中的选项。如果存在冲突,当前配置文件中的选项将覆盖基础配置文件中的选项。这使得可以在基础配置的基础上进行自定义。
多级继承:可以创建多级继承结构,其中一个配置文件可以继承另一个配置文件,然后另一个配置文件可以再继承前一个文件,以便构建复杂的配置继承链。
相对路径和绝对路径:extends 属性可以使用相对路径或绝对路径来引用基础配置文件。相对路径是相对于当前配置文件的位置计算的。
错误处理:如果 TypeScript 在加载继承的配置文件时遇到错误,它将抛出一个错误并指出问题所在。这可以帮助快速发现配置问题。
配置继承的建议:使用 extends 属性可以提高配置文件的可维护性,但需要小心管理继承关系。确保基础配置文件的更改不会意外影响到依赖它的项目。同时,确保在每个项目中都有足够的文档来描述配置继承关系和特定配置项的含义。
比如下面的三个有继承关系的配置文件:
json
// tsconfig.a.json
{
"compilerOptions": {},
"files": [
"a.ts"
],
"include": [
"src/*"
]
}
// tsconfig.b.json
{
"extends": "./tsconfig.a.json",
"files": [
"b.ts"
],
"exclude": [
"src/view/*"
]
}
// tsconfig.json
{
"extends":"tsconfig.b.json",
"files":["c.ts"]
}
当使用 ts 编译的时候, 这三个配置文件的合并结果是:
bash
$ npx tsc --showConfig
{
"compilerOptions": {},
"files": [
"./a.ts"
],
"include": [
"src/*"
],
"exclude": [
"src/view/*"
]
}
ts 官方提供了一些常用的配置文件,安装和使用方法可以点击这里
Emit 输出相关选项
outDir
如果设置了这个选项, ts 编译后生成的.js
,.d.ts
,.js.map
文件都会保存在这个目录内
如果没有设置, 生成的文件会保存在源.ts
文件的同级目录
outFile
如果设置了这个选项, ts 生成的所有文件都会保存在单个输出文件中
只有module
选项的值为None
,System
,AMD
时, 这个选项才有效
sourceMap
如果设置为true
, ts 在编译后会生成映射文件.js.map
, 并在.js
文件结尾插入 sourceMappingURL
, 像这样:
javascript
import { init } from "foo";
console.log(init);
export var add = function () {};
//# sourceMappingURL=main.js.map
mapRoot
指定sourceMappingURL
的前缀
假设有源文件:
typescript
export const foo = "foo";
没有指定mapRoot
时的输出内容:
javascript
export var foo = "foo";
//# sourceMappingURL=main.js.map
指定了"mapRoot": "http://codquan2.com"
时的输出内容:
javascript
export var foo = "foo";
//# sourceMappingURL=http://codquan2.com/main.js.map
sourceRoot
指定.js.map
文件中的sourceRoot字段
(用于指定源代码文件的根目录,通常用于调试和源映射的目的)
没有设置改选项生成的.js.map
文件:
javascript
{"version":3,"file":"main.js","sourceRoot":"","sources":["../main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAE3B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAElB,MAAM,CAAC,IAAM,GAAG,GAAG,cAAO,CAAC,CAAC"}
设置了该选项的.js.map
文件:
javascript
{"version":3,"file":"main.js","sourceRoot":"http://codequan.com/","sources":["main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAE3B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAElB,MAAM,CAAC,IAAM,GAAG,GAAG,cAAO,CAAC,CAAC"}
inlineSourceMap
把.js.map
内容放进.js
文件的末尾, 有助于在浏览器中调试 JavaScript 代码时,可以直接与 TypeScript 源代码进行关联,而不需要额外的 .map 文件
这些内容会以 base64 的格式嵌入.js
文件
inlineSource
设置为 true,则生成的 JavaScript 文件中将包含原始 TypeScript 代码
这些内容会以 base64 的格式嵌入.js
文件
declaration
设置为true
时, ts 编译后会自动生成对应的.d.ts
文件
declarationDir
正常情况下, 生成的.d.ts
文件与编译后的.js
文件在同一目录下, 通过该选项, 可以单独指定.d.ts
文件的保存目录, 大部分项目都会设置为./types
目录
declarationMap
类似于sourceMap
, 但这个选项输出的是.d.ts
文件的映射文件.d.ts.map
, 该文件与.d.ts
文件在同一个目录内
stripInternal
如果设置为true
, ts 会在输出.d.ts
文件时, 移除包含@internal
的 JSDoc 注释
如果 ts 中的某个方法, 仅用于内部使用, 不需要让使用者知道内部实现细节, 可以开启这个选项, 并在方法上添加@internal
JSDoc 注释
typescript
// main.ts
/**
* init project
*/
export function init() {}
/**
* @internal
* run project
*/
export function run() {}
// 使用默认值false, 生成的声明文件 main.d.ts
/**
* init project
*/
export declare function init(): void;
/**
* @internal
* run project
*/
export declare function run(): void;
// 设置为true, 生成的main.d.ts文件
/**
* init project
*/
export declare function init(): void;
noEmit
noEmit
当设置为 true 时,告诉 TypeScript 编译器不生成任何输出文件(如 JavaScript 文件或声明文件),
通常用于构建工具和开发环境中,以提高编译速度或仅进行类型检查。在这种情况下,编译器仅检查 TypeScript 代码并报告错误,而不会生成实际的输出文件。
noEmitOnError
用于控制是否在发现类型错误时阻止 TypeScript 编译器生成输出文件。当将 noEmitOnError
设置为 true
时,如果 TypeScript 编译器在编译过程中发现了任何类型错误,它将不会生成编译输出文件(通常是 JavaScript 文件)。
emitDeclarationOnly
emitDeclarationOnly
当设置为 true 时,告诉 TypeScript 编译器只生成声明文件(.d.ts 文件),而不生成 JavaScript 文件。这对于创建库的类型定义文件非常有用。
通常在创建库或模块的类型定义文件时使用,以确保只生成声明文件而不生成 JavaScript 文件。这允许其他开发人员在不需要实际代码的情况下使用库的类型信息。
importHelpers
ts 在对某些语法与 API 进行降级的时候, 会从tslib
中自动导入相关的函数, 比如
typescript
// main.ts
export const add = (name: string[]) => {
return ["lily", ...name];
};
// main.js
var __spreadArray =
(this && this.__spreadArray) ||
function (to, from, pack) {
if (pack || arguments.length === 2)
for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
export var add = function (name) {
return __spreadArray(["lily"], name, true);
};
上面输出文件中的__spreadArray
就是从tslib
中导入的函数, 用来降级扩展运算符
如果该选项设为true
, 告诉 ts 不自动往代码中写入__spreadArray
函数, 输出内容就变成了:
javascript
import { __spreadArray } from "tslib";
export var add = function (name) {
return __spreadArray(["lily"], name, true);
};
这个时候, 项目中就需要提前安装好tslib
库, 防止在调用__spreadArray
函数式报错
noEmitHelpers
如果设置为true
, TypeScript 编译器不会将任何辅助函数插入到生成的 JavaScript 代码中。这通常用于浏览器环境或其他运行时环境
上面案例中的输出文件内容就变成:
javascript
export var add = function (name) {
return __spreadArray(["lily"], name, true);
};
其中__spreadArray
函数就要从全局上下文中获取了
downlevelIteration
用于控制是否启用针对迭代器 的 "降级" 编译。这个选项通常与 for...of
循环结合使用,因为不同版本的 JavaScript 支持不同的迭代行为。
假设有输入文件:
typescript
const str = "Hello!";
for (const s of str) {
console.log(s);
}
正常的"降级":
javascript
var str = "Hello!";
for (var _i = 0, str_1 = str; _i < str_1.length; _i++) {
var s = str_1[_i];
console.log(s);
}
设置为true
的"降级":
javascript
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 str = "Hello!";
try {
for (
var str_1 = __values(str), str_1_1 = str_1.next();
!str_1_1.done;
str_1_1 = str_1.next()
) {
var s = str_1_1.value;
console.log(s);
}
} catch (e_1_1) {
e_1 = { error: e_1_1 };
} finally {
try {
if (str_1_1 && !str_1_1.done && (_a = str_1.return)) _a.call(str_1);
} finally {
if (e_1) throw e_1.error;
}
}
一般情况下,如果目标是支持较老版本的 JavaScript 运行时环境, 才需要将 downlevelIteration
设置为true
,以确保 for...of
循环等迭代操作能够正确运行。
removeComments
设置为true
时, 编译过程中会移除所有的注释代码
importsNotUsedAsValues
ts@5 中已弃用, 使用verbatimModuleSyntax
代替
该选线用来告诉 ts 怎么处理文件中的import
语句, 有三种值:
remove : 默认值, 会移除所有只导入没有使用的import
语句
preserve: 会保留所有从未被使用过(值或类型)的导入语句
error : 会保留所有的import
语句, 但是导入的值, 在代码中只被当做类型时, 会抛出错误, 比如:
typescript
import { User } from "./foo"; // 这句会抛出错误, 因为User被导入后, 只被用作类型
export function init(user: User) {
console.log("init");
}
// 不会提示错误的写法:
import type { User } from "./foo";
export function init(user: User) {
console.log("init");
}
preserveConstEnums
设置为true
时, ts 会保留Enum
的原始数据, 且把枚举值内联到代码中
typescript
// 编译前, main.ts
const enum Color {
red = 1,
green = 2,
blue = 3,
}
const selectedColor = Color.red;
if (selectedColor === Color.red) {
console.log("That is a great choice.");
}
// 默认值 false, 编译后:
var selectedColor = 1; /* Color.red */
if (selectedColor === 1 /* Color.red */) {
console.log("That is a great choice.");
}
// 设置为true编译后 (enum被编译为一个对象来保存枚举的key和value):
var Color;
(function (Color) {
Color[(Color["red"] = 1)] = "red";
Color[(Color["green"] = 2)] = "green";
Color[(Color["blue"] = 3)] = "blue";
})(Color || (Color = {}));
var selectedColor = 1; /* Color.red */
if (selectedColor === 1 /* Color.red */) {
console.log("That is a great choice.");
}
需要注意的是isolatdModules
设置为true
时, 也会影响枚举的编译结果, 并把该选项的值设置为true
:
javascript
// 设置为isolatdModules: true, 编译后:
var Color;
(function (Color) {
Color[(Color["red"] = 1)] = "red";
Color[(Color["green"] = 2)] = "green";
Color[(Color["blue"] = 3)] = "blue";
})(Color || (Color = {}));
var selectedColor = Color.red;
if (selectedColor === Color.red) {
console.log("That is a great choice.");
}
通常不需要启用,除非你明确需要在运行时访问常数枚举的类型信息。默认情况下,TypeScript 会将常数枚举内联到生成的代码中,以提高性能和减小文件大小。
preserveValueImports
ts@5 版本已启用, 推荐使用verbatimModuleSyntax
在某些特殊情况下, ts 无法检测到导入的内容是否被使用, 比如:
typescript
import { defualtUser } from "./foo";
eval("console.log(defaultUser)");
当该选项设为 true
的时候, 将强制 ts 保留这类import
语句
newLine
设置输出文件的行尾类型, 有crlf(dos)
和lf(unix)
两种值
emitBOM
该选项默认值是 false, 且通常不需要关注该选项
用于控制是否在输出文件中包含字节顺序标记(Byte Order Mark,BOM)。
设置为true
时, 输出文件会包含字节顺序标记
BOM 是一个特殊的字符,通常在 Unicode 编码文件中的开头用于标识文件的编码方式。
Env,Language 环境及设置相关选项
target
用于指定编译后的 JavaScript 代码应该符合的 ECMAScript 版本
以下是 target 选项的一些常见值和它们的含义:
可用值 | 说明 |
---|---|
ES3 | 编译为 ECMAScript 3(ES3)版本的 JavaScript。这是较旧的 ECMAScript 版本,支持在更古老的浏览器中运行。TS@5.5 版本开始可能会停用这个选项, 慎用 |
ES5 | 编译为 ECMAScript 5(ES5)版本的 JavaScript。ES5 支持较新的 JavaScript 特性,适用于现代浏览器。 |
ES2015(或 ES6) | 编译为 ECMAScript 2015(ES2015,也称为 ES6)版本的 JavaScript。ES2015 引入了一些重要的新特性,如箭头函数、模块、类等。 |
ES2016 | 编译为 ECMAScript 2016(ES2016)版本的 JavaScript。ES2016 引入了一些小的语言改进。 |
ES2017 | 编译为 ECMAScript 2017(ES2017)版本的 JavaScript。ES2017 引入了异步函数等功能。 |
ESNext | 编译为最新的 ECMAScript 标准(通常是草案或未来标准的一部分)。这意味着使用最新的 JavaScript 特性,但可能不适用于所有 JavaScript 运行时。 |
选择适当的 target 取决于你的目标环境。如果代码将在现代浏览器中运行,通常可以选择 ES6(ES2015)或更高版本。如果需要支持较老的浏览器或特定的 JavaScript 运行时,可能需要选择较低的版本。
以ES5
为例, 可以看到语法中的const
被改为var
; 箭头函数被改为function
; 模板字符串也被转为字符串拼接:
typescript
// tsconfig.json
{
"files": [
"main.ts",
],
"compilerOptions": {
"module": "ESNext",
"target": "ES5",
}
}
// 编译前
export function init() {
const a = 1;
const b = () => {};
const c = `${a}=1`;
}
// 编译后
export function init() {
var a = 1;
var b = function () { };
var c = "".concat(a, "=1");
}
lib
ts 内置了一套和 JS 相匹配的类型库, 比如 JS 的Math
,Navigator
,或者浏览器的Window
,Document
等, 该选项决定了 TypeScript 编译器应该为你的代码提供哪些类型定义和内置对象的支持,以帮助你进行类型检查和开发时的提示
选项的值是一个string[]
类型, 可用值包括ES5
,ES2015
,ES6
,ES2016
等一系列值, 还可以添加某些单独的库组件,比如DOM.Iterable
,ES2015.Generator
等,完整的清单可以查看 ts 的lib 库文件
lib
选项可以与target
组合使用: 设置target
选项, 会修改lib
选项的默认值, lib
选项则可以在target
包含的类型库之外额外添加一些类型库
javascript
// tsconfig.js
{
"files": [
"main.ts",
],
"compilerOptions": {
"module": "ESNext",
"target": "ES5",
"lib": [
"ESNext" // 如果没有这个选项, 下面main.ts中的Promise会抛出异常, 因为target:ES5中不包含Promise相关的API, ts就无法识别Promise
]
}
}
// main.ts
export function init() {
return new Promise((res) => {
res({});
});
}
noLib
用于禁用默认的 TypeScript 类型库(lib)的引入。当你设置 noLib 为 true 时,TypeScript 将不会自动包含默认的类型库,包括 ES6、DOM 和其他内置类型。
这个选项通常用于特殊情况,例如,当你希望完全自定义哪些类型库应该包含在你的项目中,而不希望 TypeScript 自动引入默认的类型库。
禁用默认类型库可能会导致你在编写代码时缺少一些常见的类型定义,因此在绝大多数项目中,不建议启用 noLib。通常情况下,建议使用默认的 TypeScript 类型库,以便充分利用 TypeScript 的类型检查和提示功能。
experimentalDecorators
启用装饰器功能
emitDecoratorMetadata
设置为true
时, ts 会把被装饰器装饰的元数据信息保存到输出的.js
文件中
经实测,只有
class method
和class method params
的信息会被保存,class
本身没有元数据, 不会被存储
typescript
// 编译前 main.ts
// 未启用该选项编译后:
var __decorate =
(this && this.__decorate) ||
function (decorators, target, key, desc) {
var c = arguments.length,
r =
c < 3
? target
: desc === null
? (desc = Object.getOwnPropertyDescriptor(target, key))
: desc,
d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if ((d = decorators[i]))
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
function LogMethod(target, propertyKey, descriptor) {
console.log(target);
console.log(propertyKey);
console.log(descriptor);
}
class Demo {
foo(bar) {
// do nothing
}
}
__decorate([LogMethod], Demo.prototype, "foo", null);
const demo = new Demo();
// 启用该选项编译后:
var __decorate =
(this && this.__decorate) ||
function (decorators, target, key, desc) {
var c = arguments.length,
r =
c < 3
? target
: desc === null
? (desc = Object.getOwnPropertyDescriptor(target, key))
: desc,
d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if ((d = decorators[i]))
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata =
(this && this.__metadata) ||
function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
return Reflect.metadata(k, v);
};
function LogMethod(target, propertyKey, descriptor) {
console.log(target);
console.log(propertyKey);
console.log(descriptor);
}
class Demo {
foo(bar) {
// do nothing
}
}
__decorate(
[
LogMethod,
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number]),
__metadata("design:returntype", void 0),
],
Demo.prototype,
"foo",
null
);
const demo = new Demo();
jsx
允许在 ts 中使用 jsx 语法
在 ts 中启用 jsx 语法, 需要安装
react react-dom @types/react @types/react-dom
模块, 且必须在入口文件中引入import React from 'react'
jsx 的值只允许以下几种:
typescript
// main.tsx
import React from "react";
export const HelloWorld = () => <h1>Hello world</h1>;
javascript
// react 默认值, jsx语法会被替换为React.createElement函数
import React from "react";
export const HelloWorld = () => React.createElement("h1", null, "Hello world");
// react-jsx 指定使用 react/jsx-runtime.js 文件(在 node_modules/react 内)中的函数解析 jsx
import { jsx as _jsx } from "react/jsx-runtime";
export const HelloWorld = () => _jsx("h1", { children: "Hello world" });
// react-jsxdev 指定使用 react/jsx-dev-runtime.js 文件(在 node_modules/react 内)中的函数解析 jsx
import { jsxDEV as _jsxDEV } from "react/jsx-dev-runtime";
const _jsxFileName =
"/Users/loki/Documents/office/aprojects/zhongke/vary-ui/ts/main.tsx";
export const HelloWorld = () =>
_jsxDEV(
"h1",
{ children: "Hello world" },
void 0,
false,
{ fileName: _jsxFileName, lineNumber: 3, columnNumber: 32 },
this
);
// preserve 保留源代码, 不做任何处理, 输出 .jsx 文件
import React from "react";
export const HelloWorld = () => <h1>Hello world</h1>;
// react-native 保留原代码, 不做任何处理, 但输出 .js 文件
import React from "react";
export const HelloWorld = () => <h1>Hello world</h1>;
reactNamespace
已被废弃, 使用新的选项jsxFactory
代替. 使用自定义或第三方的解析函数, 替换React.createElement
jsxFactory
如果 tsx 中的 jsx 内容不想使用React.createElement
来解析, 想使用自定义或者第三方的解析函数, 该选项用来指定替换React.createElement
的函数名
比如, 有的项目会使用preact
中的h
函数来代替React.createElement
:
typescript
// tsconfig.json
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h",
}
}
// main.tsx
import {h} from 'preact'
export const HelloWorld = () => <h1>Hello world</h1>;
// 编译后的 main.js, 这里的 h 代替了 React.createElement
import { h } from 'preact';
export const HelloWorld = () => h("h1", null, "Hello world");
jsxFragmentFactory
该选项是为了适配 React18 中引入的新特性Fragment
新增的, 如果在项目中想使用自定义的或者第三方的 jsx 片段构造函数, 可以使用该选项来设置 jsx 片段构造函数的名称;
比如, 使用 preact
提供的Fragment
来代替React.Fragment
:
先看看使用react
的情况:
typescript
// tsconfig.json
{
"compilerOptions": {
"jsx": "react",
}
}
// main.tsx
import React from 'react'
export const HelloWorld = () => <><h1>Hello world</h1></>;
// main.js
import React from 'react';
export const HelloWorld = () => React.createElement(React.Fragment, null,
React.createElement("h1", null, "Hello world"));
再看看使用preact
替换 jsx 片段构造函数的:
typescript
// tsconfig.json
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment",
}
}
// main.tsx
import { h, Fragment } from "preact";
export const HelloWorld = () => (
<>
<h1>Hello world</h1>
</>
);
// main.js
// 这里React.createElement被preact的h函数替换, React.Fragment被preact.Fragment替换
import { h, Fragment } from 'preact';
export const HelloWorld = () => h(Fragment, null,
h("h1", null, "Hello world"));
需要注意的是, 该选项, 必须与jsxFactory
搭配使用, 不能单独设置
jsxImportSource
当jsx
选项设置为react-jsx
或者react-jsxdev
时, 该选项用来从自定义或者第三方的模块中导入 JSX 标识符
比如:
typescript
// tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
}
}
// main.tsx
import React from "react";
export const HelloWorld = () => (
<>
<h1>Hello world</h1>
</>
);
// main.js 这里jsx, Fragment都是从"react/jsx-runtime"导入的
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
export const HelloWorld = () => _jsx(_Fragment, { children: _jsx("h1", { children: "Hello world" }) });
如果使用preact
模块作为导入来源时:
typescript
// tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}
// main.js 这里jsx, Fragment都是从"preact/jsx-runtime"导入的, 其他都没有变化
import { jsx as _jsx, Fragment as _Fragment } from "preact/jsx-runtime";
export const HelloWorld = () => _jsx(_Fragment, { children: _jsx("h1", { children: "Hello world" }) });
moduleDetection
该选项用来控制 ts 如何识别某个文件是不是 module, ts 对模块的分辨逻辑可以参考官方文档
该选项有三种值:
auto : 默认值, 当module
选项设置为Node16
或者NodeNext
时, ts 不仅通过**文件中是否有顶级的 export
或者import
**来识别模块, 还会通过package.json
文件中的type
字段是否为module
来识别模块; 如果jsx
选项被设置为react-jsx
, ts 还会根据被导入文件的后缀是不是.jsx
或者.tsx
来识别模块
legacy : ts@4.6 及之前版本的默认值, 表示 ts 只通过**文件中是否有顶级的 export
或者import
**来识别模块
force :把所有非.d.ts
等声明文件都视为模块
暂不清楚该选项的使用场景
useDefineForClassFields
ES2022 版本开始, 可以在Class
中以下面的方式添加类本身的属性:
javascript
// ES2022版本之前
class C {
constructor() {
this.foo = 100;
}
}
// ES2022版本之后的 Class Fields语法
class C {
foo = 100;
}
这种写法允许在类中直接定义实例字段而不需要在构造函数中进行初始化。这提供了更简洁的语法来定义类的属性。
该选项告诉 ts 生成的代码中是否允许使用Class fields
语法
当target
被设置为**ES2022
及以上**的值是, 该选项自动设置为true
, 否则就自动设置为false
通常情况下, 该选项不需要人为设置
Modules 模块解析相关选项
module
用于设置编译后输出文件 的(模块)类型,可以不设置, 默认值是commonjs
假如你有这样一个文件(官方案例):
typescript
// @filename: index.ts
import { valueOfPi } from "./constants";
export const twoPi = valueOfPi * 2;
module
的可用值以及输出格式有以下选项:
javascript
// CommonJS
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.twoPi = void 0;
const constants_1 = require("./constants");
exports.twoPi = constants_1.valueOfPi * 2;
// amd
define(["require", "exports", "./constants"], function (
require,
exports,
constants_1
) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.twoPi = void 0;
exports.twoPi = constants_1.valueOfPi * 2;
});
// 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", "./constants"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.twoPi = void 0;
const constants_1 = require("./constants");
exports.twoPi = constants_1.valueOfPi * 2;
});
// system
System.register(["./constants"], function (exports_1, context_1) {
"use strict";
var constants_1, twoPi;
var __moduleName = context_1 && context_1.id;
return {
setters: [
function (constants_1_1) {
constants_1 = constants_1_1;
},
],
execute: function () {
exports_1("twoPi", (twoPi = constants_1.valueOfPi * 2));
},
};
});
// es6 | es2015 | es2020 | es2022
import { valueOfPi } from "./constants";
export const twoPi = valueOfPi * 2;
import { valueOfPi } from "./constants";
export const twoPi = valueOfPi * 2;
// node16 | nodenext
//
上面node16 | nodenext
没有给出具体的格式案例, 是以为从 ts@4.7 开始 node16 与 nodenext 输出的格式取决于文件扩展名与 package.json 文件中的 type 字段:
条件 | 输出格式 |
---|---|
package.json.type: "module" | esm 格式 |
package.json.type: "commonjs" | CommonJS 格式 |
文件扩展名: .mjs 或者.mts |
esm 格式 |
文件扩展名: .cjs 或者.mts |
CommonJS 格式 |
moduleResolution
用于设置模块的解析策略, 与module
搭配使用, 有以下几种选项
-
Classic
: 是 ts@1.6 之前版本的默认值, 现在保留这种策略主要是为了向后兼容, 现在基本上用不到这个选项了, 除非需要与特殊的模块配合使用 -
Node
: 指的是模仿NodeJS
的模块路径解析模式来查找文件, 可与module
选项任意值搭配使用 -
Node10
: 与Node
相同, 是 ts@5.2.2 中Node
的别名 -
Node16
: 必须 与"module": "Node16"
配合使用, 不同的是, 生成的文件中,会保留文件中ES6+
中的新语法(const
,let
,箭头函数
等) -
NodeNext
: 必须 与"module":"NodeNext"
配合使用, 其他与Node16相同
-
Bundler
: 要求module
选项的值必须 是ESM
类(以ES
开头)的值, 生成的文件也是是ES模块
Classic
与Node
两种解析方式的不同之处可以直接参考官方文档; 这里只说 ts 中的node
解析模式:
moduleSuffixes
该选项用来覆盖解析模块时要搜索的默认文件名后缀列表
假设有以下配置和文件
typescript
// tsconfig.json
{
"compilerOptions": {
"moduleSuffixes": [".ios", ".native", ""]
}
}
// main.ts
import * as foo from "./foo";
ts 将会查找./foo.ios.ts
,./foo.native.ts
,./foo.ts
此选项多用于 React Native 项目
需要注意的是"moduleSuffixes": [".ios", ".native", ""]
中有一个""
, 这是不可缺少的, 没有它, ts 就不会查找./foo.ts
baseUrl
该选项主要用于告诉 ts 在相对于哪个目录解析非相对路径模块
如果选项值是一个相对路径, 则根据tsconfig.json
所在位置计算
typescript
// /a.ts
export function init() {
console.log("./a");
}
// /src/a.ts
export function init() {
console.log("./src/a");
}
// /main.ts
import { init } from "a"; // 这里的 "a" 会被解析到 src/a.ts
export function foo() {
init();
}
// tsconfig.json
{
"files": [
"main.ts",
],
"include": [
"*/src/**/*.ts"
],
"compilerOptions": {
"baseUrl": "./src",
}
}
paths
用于定义模块导入路径的别名。通过使用 paths
选项,可以将特定的导入路径映射到不同的实际文件路径,从而使导入更灵活和可配置。这对于管理模块的路径和重定向导入非常有用
path
的值是相对于baseUrl
来解析的, 把上面的案例改一下:
typescript
// /a.ts
export function init() {
console.log("./a");
}
// /src/a.ts
export function init() {
console.log("./src/a");
}
// /lib/a.ts
export function init() {
console.log("./lib/a");
}
// /main.ts
import { init } from "a"; // 这里的 "a" 会被解析到 lib/a.ts
export function foo() {
init();
}
// tsconfig.json
{
"files": [
"main.ts",
],
"include": [
"*/src/**/*.ts"
],
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"a": [
"../lib/a.ts"
]
}
}
}
在平时比较常见的配置:
javascript
{
"compilerOptions": {
"baseUrl": "./src",
"path": {
"@app/*":['../app'],
"@lib/*":['../lib'],
}
}
}
所以paths
的权重要高于baseUrl
的权重
noResolve
用于控制是否启用 TypeScript 编译器的模块解析(module resolution)功能。当将 noResolve
设置为 true
时,它会告诉编译器不要执行模块解析,也就是不要查找和加载模块的依赖关系
通常情况下,不太需要显式地设置 noResolve
选项,因为 TypeScript 编译器会自动执行模块解析以查找和加载依赖的模块。但在一些情况下,可能会需要手动控制模块解析的过程,这时可以考虑使用 noResolve。
在某些情况下,如果知道项目中没有模块依赖关系需要解析,可以将 noResolve
设置为 true
以加快编译速度
customConditions
ts 在模拟 nodejs 的模块解析功能时, 如果模块来自node_modules
, ts 会从模块的package.json.exports
属性中读取文件, customConditions
用于使用自定义导出条件
需要注意的是: package.json.exports
属性只有package.json.type
为module
时才有效, 所以customConditions
选项也是有条件的:
Option 'customConditions' can only be used when 'moduleResolution' is set to 'node16', 'nodenext', or 'bundler')
resolveJsonModule
默认值false
, 设置为true
时, 允许导入扩展名为 .json
的模块,这是项目中的常见做法。这包括根据静态 JSON 形状生成导入类型
resolvePackageJsonImports
当从一个文件导入以#
开头的value
或者type
时, 如果这个文件所在的目录(或者祖先目录)内有一个package.json
文件, 开启这个选项会强制 ts 从package.json.imports
字段确认导入的实际文件
当moduleResolution
设置以为Node16
,NodeNext
,Bundler
时, 该选项的默认值自动设置为true
暂不清楚该选项的使用场景
resolvePackageJsonExports
主要用于处理 package.json
文件中的 exports
字段,以更好地支持导入不同版本的 JavaScript 模块
当moduleResolution
设置以为Node16
,NodeNext
,Bundler
时, 该选项的默认值自动设置为true
暂不清楚该选项的使用场景
allowArbitraryExtensions
正常情况下, ts 不允许在文件中导入.ts
或者.tsx
文件, 只允许使用标准的 js 文件扩展名.js
或者.jsx
如果在 ts 文件中导入了非正常扩展名的文件, 需要像下面这样添加一个对应的.d.ts
文件明确告诉 ts 该文件的类型:
typescript
// main.js
import css from 'app.css'
console.log(css.mainColor)
// app.css
.mainColor{
color: red
}
// app.css.d.ts
declare const css: {
mainColor: string
}
我启用了allowArbitraryExtensions
后,没啥反应
allowImportingTsExtensions
启用该选项时, 允许在导入.ts
, .mts
,或者.tsx
文件时省略文件后缀, 但是只有当noEmit
或者emitDeclarationOnly
启用时, 这个选项才能开启
ts@5.2.2 中这个选项默认值应该是
true
, 因为我没有启用它, ts 也没有对省略后缀的语句报错
allowUmdGlobalAccess
暂不清楚使用场景
rootDir
rootDirs
types 与 typeRoot
当项目中引入了一个第三方的库, 且该库没有提供官方的类型声明文件时, ts 不会报错, 但会做如下处理:
typescript
// main.ts
import { init } from "foo";
// 上面的语句会提示: 无法找到模块"foo"的声明文件。"/Users/loki/Documents/office/aprojects/zhongke/vary-ui/ts/node_modules/foo/index.js"隐式拥有 "any" 类型
export function initMain() {
console.log(init);
}
这种情况下, 通常需要我们手动给模块foo
添加一个类型声明文件, 以支持 ts 进行类型检查或者支持编辑器自动识别类型
其中typeRoots
用来告诉 ts 自定义类型声明文件所在的目录位置,
types
用来告诉 ts 要加载的类型声明文件名称
像上面的案例, 我们可以添加如下配置:
typescript
// tsconfig.json
{
compilerOptions:{
"typeRoots": [
// 假设自定义类型声明文件都放在./customer-types目录内
"./customer-types"
],
"types": [
"foo" // 告诉ts加载目录内的 foo.d.ts 文件
],
}
}
// ./customer-types/foo.d.ts
declare module "foo" {
export function init(): void;
}
还有一种使用场景是, 假设你的项目中使用了一个全局变量:
typescript
// main.ts
export function initMain() {
console.log(globalConfig.env);
}
可以添加下面的配置解决这个问题:
typescript
// tsconfig.json
{
compilerOptions:{
"typeRoots": [
// 假设自定义类型声明文件都放在./customer-types目录内
"./customer-types"
],
"types": [
"index" // 告诉ts加载目录内的 index.d.ts 文件
],
}
}
// ./customer-types/index.d.ts
declare var globalConfig: {
env: string;
};
typeChecking 类型检查相关选项
alwaysStrict
alwaysStrict
用来控制生成的 JS 文件 具有use strict
标记, 该行为让生成的 js 文件以严格模式执行
strict
strict
则是用来控制 ts 在编译过程中对 ts 文件中某些行为的处理 , 它包含了一系列的选项: strictNullChecks
,strictBindCallApply
,strictFunctionTypes
,noImplicitAny
,noImplicitThis
,strictPropertyInitialization
,useUnknownInCatchVariables
等, 如果strict
设为 true, 则这些选项都会被启用
也可以在
strict
为true
的情况下, 单独关闭某些选项, 像这样:
json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": false
}
}
strict
是一系列选项的集合, 它包含的选项可能会随着 ts 版本的升级而变化
strictNullChecks
如果设置为true
, 下面这段代码在 ts 编译是会产生编译错误, 因为loggedInUser
的值可能是null
typescript
declare const loggedInUsername: string;
const users = [
{ name: "Oby", age: 12 },
{ name: "Heera", age: 32 },
];
const loggedInUser = users.find((u) => u.name === loggedInUsername);
console.log(loggedInUser.age); // 编译错误
strictBindCallApply
设置为true
后, ts 将会检查使用call
,bind
,apply
调用函数时,参数的传递情况, 比如下面的案例中, ts 会产生编译错误, 因为函数fn
需要的是字符串类型的参数
typescript
// With strictBindCallApply on
function fn(x: string) {
return parseInt(x);
}
const n1 = fn.call(undefined, "10");
const n2 = fn.call(undefined, false); // Argument of type 'boolean' is not assignable to parameter of type 'string'.
strictFunctionTypes
设置为true
时, 会对函数参数启用更严格的检查, 下面的案例就会产生编译错误,因为函数func
的类型与函数fn
的参数类型并不相同, 所以不能直接赋值
typescript
function fn(x: string) {
console.log("Hello, " + x.toLowerCase());
}
type StringOrNumberFunc = (ns: string | number) => void;
let func: StringOrNumberFunc = fn;
// Type '(x: string) => void' is not assignable to type 'StringOrNumberFunc'.
// Types of parameters 'x' and 'ns' are incompatible.
// Type 'string | number' is not assignable to type 'string'.
// Type 'number' is not assignable to type 'string'.
noImplicitAny
设置为true
时, 如果函数参数没有指定类型, ts 会产生编译错误, 比如下面的案例中参数s
没有指定类型,
typescript
function fn(s) {
// Parameter 's' implicitly has an 'any' type.
console.log(s.subtr(3));
}
noImplicitThis
设置为true
时, 用于控制是否允许在函数中使用不明确的 this 上下文,除非进行了明确的指定。这个选项可以帮助防止 this 上下文的潜在错误,特别是在面向对象编程和事件处理等情况下。它促使开发人员更加谨慎地处理 this 上下文,从而提高代码的可读性和类型安全性。
下面的代码中, this
就是一个不明确的上下文, 如果想修复这个问题, 可以把函数改为箭头函数,或者手动给this
指定明确的类型
typescript
function logMessage(message: string) {
console.log(this); // Error: 'this' implicitly has type 'any'
console.log(message);
}
const obj = {
name: "John",
log: logMessage,
};
obj.log("Hello, TypeScript!");
strictPropertyInitialization
当设置为 true
时,TypeScript 编译器会要求类中的属性必须在构造函数中进行初始化或者在属性声明时提供初始值。如果没有满足这些条件,编译器会产生一个错误,表示属性可能处于未定义的状态,这有助于避免在运行时出现未定义属性的错误
在下面的示例中,由于属性 name
声明的时候没有初始化值, 又没在构造函数中赋值,TypeScript 会产生一个错误,指出属性 name
可能处于未定义的状态
typescript
class Person {
name: string; // Error: Property 'name' has no initializer and is not definitely assigned in the constructor.
}
const person = new Person();
console.log(person.name); // Potential runtime error: 'name' is undefined
useUnknownInCatchVariables
TypeScript 4.0 版本引入的一个编译器选项
当设置为 true
时,TypeScript 会将 catch
子句中的异常变量的类型隐式推断为unknown
。这意味着在catch
子句中,异常变量将被视为具有unknown
类型,需要显式进行类型检查或类型断言才能使用它们。
在下面的示例中,error
未指明类型, error.message
在运行时可能会报错,
typescript
try {
// 一些可能抛出异常的操作
} catch (error) {
// 在useUnknownInCatchVariables默认情况下,error 被推断为 any 类型
console.log(error.message); // ts编译不会报错,但可能在运行时出错
}
如果把useUnknownInCatchVariables
设置为true
, error
会被隐式推断为unknown
类型, unknown
类型的error
是不允许任何操作的, 所以在编译过程中, ts 会产生编译错误
allowUnreachableCode
默认值 false
, 用于控制是否允许编写包含不可达代码(unreachable code)的 TypeScript 文件。不可达代码是指永远不会被执行到的代码,它通常是错误或者不必要的。
比如下面的代码中:
javascript
function divide(a: number, b: number): number {
if (b === 0) {
return Infinity;
}
return a / b;
console.log("This line is unreachable"); // 不可达代码
}
ts 在编译这段代码的时候, 就会产生一个编译错误
这种 unreachable 代码会导致代码不清晰, 所以尽量保持它为true
allowUnusedLabels
用于控制是否允许在代码中定义但未使用的标签(labels)。标签通常与循环(如 for、while)和 break 或 continue 语句一起使用,用于跳出或跳转到指定的代码块。
设为true
的时候可以允许未使用的标签存在,而不会产生编译错误
通常情况下,建议将 allowUnusedLabels 保持为默认值 false,以确保代码的清晰性和可维护性。未使用的标签通常是代码中的无用元素,可能会使代码更难以理解。
typescript
// 在默认情况下,未使用的标签会导致编译错误
label1: for (let i = 0; i < 3; i++) {
console.log(i);
}
// 如果启用了 allowUnusedLabels,将不会产生编译错误
label2: for (let i = 0; i < 3; i++) {
console.log(i);
}
exactOptionalPropertyTypes
在默认值false
的时候, 下面的代码中, color
可以被设置为三种值: dark
,light
,或者undefined
, 在项目运行时color is not defined
和color=undefined
是两个不同的概念,
设置为true
时, 下面的代码会产生编译错误, 因为 ts 将不会允许把undefined
赋值给color
typescript
interface UserDefaults {
color?: "dark" | "light";
}
const user: UserDefaults = {};
user.color = undefined; // Error: 类型 "undefined" 不能分配给"exactOptionalPropertyTypes: true"的类型 ""dark" | "light""。请考虑将 "undefined" 添加到目标类型。
noFallthroughCasesInSwitch
设置为true
时, ts 会检查switch case
中的case
语句中是否包含break,continue,return
, 如果没有包含, ts 会产生编译错误. 启用 noFallthroughCasesInSwitch
选项有助于防止在 switch 语句中不经意地出现 fallthrough 的情况,从而提高代码的可维护性和可读性。这对于确保每个 case 都是明确且独立的情况下非常有用。
typescript
// 在默认值false的时候,不带 break 的 case 是合法的, 设为true后, ts会报错
function getResult(option: string): number {
let result = 0;
switch (option) {
case "A":
result += 10;
// 没有 break,流入到下一个 case
case "B":
result += 20;
break;
case "C":
result += 30;
break;
}
return result;
}
noImplicitOverride
默认值为false
时,下面的代码中是不会产生编译异常的, 如果设为true
, animal.speak();
会产生编译异常. 因为此时 TypeScript 编译器会要求子类中对父类的成员进行重写时,必须使用 override
关键字明确指定
该选项有助于确保子类正确地重写了父类的成员,从而提高代码的类型安全性。这对于维护大型项目和确保正确的多态行为非常有用
typescript
class Animal {
speak() {
console.log("Animal speaks");
}
}
class Dog extends Animal {
speak() {
console.log("Dog barks");
}
}
// 如果启用了 noImplicitOverride,下面的代码将会产生错误
const animal: Animal = new Dog();
animal.speak(); // Error: Property 'speak' in type 'Animal' is not assignable to the same property in base type 'Dog'.
noImplicitReturns
当设置为 true
时,TypeScript 编译器会要求函数内部的所有代码路径都必须具有明确的返回语句或返回类型。如果设置为 false
(默认值),则不会强制要求明确的返回。
该选项有助于确保函数内部的所有代码路径都具有明确的返回语句或返回类型,从而提高代码的类型安全性。这对于防止潜在的运行时错误和类型不一致问题非常有用。
typescript
// 在默认情况下,不要求明确的返回
function add(a: number, b: number): number {
if (a && b) {
return a + b;
}
// 缺少明确的返回语句,但不会产生编译错误
}
// 如果启用了 noImplicitReturns,下面的代码将会产生错误
function subtract(a: number, b: number): number {
if (a && b) {
return a - b;
}
// Error: Function lacks ending return statement and return type does not include 'undefined'.
}
noPropertyAccessFromIndexSignature
当设置为 true
时,TypeScript 编译器会禁止通过索引签名访问没有明确声明的属性
该选项有助于防止在代码中意外访问未明确声明的属性,从而提高代码的类型安全性。这对于确保对象属性的类型安全性非常有用。
typescript
interface MyDictionary {
[key: string]: string;
}
const dictionary: MyDictionary = {
apple: "fruit",
car: "vehicle",
};
// 如果启用了 noPropertyAccessFromIndexSignature,下面的代码将会产生错误
const fruit = dictionary.apple; // Error: Element implicitly has an 'any' type because index expression is not of type 'number'.
noUncheckedIndexedAccess
当设置为 true
时,TypeScript 编译器会要求在索引操作中明确处理 null
和 undefined
检查。这意味着在访问数组元素或对象属性之前,必须先确保索引不为 null
或 undefined
,或者使用可选链式操作符 ?.
进行安全访问。
typescript
// 在默认情况下,允许省略 null 和 undefined 检查
function getElement(arr: string[], index: number): string {
return arr[index]; // 没有 null 或 undefined 检查
}
const myArray: string[] = ["apple", "banana", "cherry"];
const result = getElement(myArray, 3); // 不会产生编译错误,但可能在运行时出错
// 如果启用了 noUncheckedIndexedAccess,下面的代码将会产生错误
// const result = getElement(myArray, 3); // Error: Object is possibly 'undefined'.
如果启用了这个检查, 上面的代码必须以下面的任意一种方式处理(这两种方式都要求在返回值中添加| undefined
类型):
第一种方式:
typescript
// 使用可选链式操作符
function getElement(arr: string[], index: number): string | undefined {
return arr[index]?.toString();
}
const myArray: string[] = ["apple", "banana", "cherry"];
const result = getElement(myArray, 3); // 不会产生编译错误,result 为 undefined
第二种方式
typescript
// 手动检查索引
function getElement(arr: string[], index: number): string | undefined {
if (index >= 0 && index < arr.length) {
return arr[index];
}
return undefined;
}
const myArray: string[] = ["apple", "banana", "cherry"];
const result = getElement(myArray, 3); // 不会产生编译错误,result 为 undefined
noUnusedLocals
noUnusedLocals
设置为true
时, ts 会检查代码中未使用的变量, 并在编译过程中产生编译错误, 比如下面的案例:
typescript
const createKeyboard = (modelID: number) => {
const defaultModelID = 23;
// Error: 'defaultModelID' is declared but its value is never read.
return { type: "keyboard", modelID };
};
noUnusedParameters
noUnusedParameters
设置为true
时, ts 会检查函数中未使用的参数, 并在编译过程中产生编译错误, 比如项目的案例:
typescript
const createDefaultKeyboard = (modelID: number) => {
// Error: 'modelID' is declared but its value is never read.
const defaultModelID = 23;
return { type: "keyboard", modelID: defaultModelID };
};
JS 相关选项
allowJs
该选项设置为true
后, 允许在.ts
文件中引入.js
文件
在 ts@5.2.2 版本测试时, 引入
.js
文件时编译没有抛出异常
checkJs
该选项设置为true
后, ts 将会检查.js
文件中的语法错误
比如:
javascript
// 这里会抛出异常, 因为parseFloat 仅接受一个字符串作为参数
module.exports.pi = parseFloat(3.124);
Editor 编辑器相关选项
disableSizeLimit
ts 默认有一个内存使用上限, 来避免处理项目时内存使用量过高, 当项目确实比较大时, 该选项可以取消这个内存使用上限
javascript
// tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"disableSizeLimit": "true"
}
}
plugins
这个选项用来配置一些基于 ts 的插件, 常用于编辑器中的语法高亮等功能
比如 NodeJS 项目中可能需要写一些 SQL 语句, ts-sql-plugin
插件就可以提供 SQL 语法高亮的功能
再比如typescript-styled-plugin插件可以为 ts 中的 CSS 样式内容提供语法高亮功能
Interop Constraints 互相操作约束(针对 CommonJS 模块)
allowSyntheticDefaultImports
用于控制在导入 CommonJS 模块时是否允许合成默认导出(synthetic default imports)
在该选项开启的模式下, 假设你有一个 commonjs 的模块:
typescript
// src/foo.js
exports.init = "foo init";
// src/foo.d.ts
export const init: string;
// main.ts
import foo from "foo";
上面的./src/foo.js
中没有exports.default
(没有默认导出), 但allowSyntheticDefaultImports
选项让 ts 对该文件进行了合成默认导出操作, 所以不会抛出错误
如果把该选项设置为false
, ts 会报错:
typescript
// tsconfig.json
{
"compilerOptions": {
"allowSyntheticDefaultImports": false
}
}
// main.ts
import foo from "foo"; // Error: 模块""/Users/loki/Documents/office/aprojects/zhongke/vary-ui/ts/src/foo""没有默认导出。
esModuleInterop
该选项用于控制在导入 CommonJS 模块(通常是 Node.js 模块)时是否启用额外的互操作性特性;
当module
选项设置为Node16
或者NodeNext
时, 该选项自动设置为true
, 否则设置为false
目前没有发现启用该选项到底有什么优势, 也不清楚引入该选项的出发点是什么, 下面只说启用该选项与未启用该选项编译结果的不同
启用该选项时, 会自动启用allowSyntheticDefaultImports选项
举个例子, 假设有这么一个模块foo
:
typescript
// node_modules/foo/index.js
exports.init = "foo init";
exports.default = "default";
// node_modules/foo/index.d.js
export const init: string;
export default init;
// tsconfig.json
{
"compilerOptions": {
"module": "CommonJS",
"target": "ES5",
"moduleResolution": "Node10",
}
}
如果想在main.ts
中导入foo
中的默认导出, 或者具名导出, 必须这样写:
typescript
// main.ts
import * as foo from "foo"; // 第一种引用方式
console.log(foo);
// 第一种编译后 main.js
("use strict");
Object.defineProperty(exports, "__esModule", { value: true });
var foo = require("foo");
console.log(foo); // { init: 'foo init', default: 'default' }
/* ---------------------------*/
// main.ts
import foo from "foo"; // 第二种引用方式
console.log(foo);
// 第二种编译后 main.js
("use strict");
Object.defineProperty(exports, "__esModule", { value: true });
var foo_1 = require("foo");
console.log(foo_1.default); // 'default'
这两种写法输出结果不同的原因从输出文件就可以看出来: 是因为在 ts 中, 命名导入语句import * as foo from "foo"
被处理成const foo = require("foo")
, 默认导入语句import foo from "foo"
被处理成const foo = require("foo").default
ts 这样处理的原因是: 在 ES6 规范中,import * as foo from "foo"
指的是用来导入"foo"模块内的全部导出export xxx
; 而import foo from "foo"
指的是用来导入"foo"模块的默认导出export default
如果把该选项设置为true
, 会统一这两种导入方式的过程, 下面是启用该选项后, 两种不同方式的编译结果:
javascript
// 采用 import foo from "foo" 的编译结果:
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var foo_1 = __importDefault(require("foo"));
console.log(foo_1.default);
// 采用 import * as foo from "foo" 的编译结果:
("use strict");
var __createBinding =
(this && this.__createBinding) ||
(Object.create
? function (o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (
!desc ||
("get" in desc ? !m.__esModule : desc.writable || desc.configurable)
) {
desc = {
enumerable: true,
get: function () {
return m[k];
},
};
}
Object.defineProperty(o, k2, desc);
}
: function (o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
});
var __setModuleDefault =
(this && this.__setModuleDefault) ||
(Object.create
? function (o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}
: function (o, v) {
o["default"] = v;
});
var __importStar =
(this && this.__importStar) ||
function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null)
for (var k in mod)
if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
__createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
var foo = __importStar(require("foo"));
console.log(foo);
// 采用 import foo from "foo" 的输出结果 { init: 'foo init', default: 'default' }
// 采用 import * as foo from "foo" 的输出结果 { init: [Getter], default: { init: 'foo init', default: 'default' } }
可以看到, 启用该选项后, 经过 ts 的特殊处理, 这两种导入方式输出的结果是"基本一致"的
forceConsistentCasingInFileNames
默认是true
, 用于控制文件名的一致性检查。该选项会影响 TypeScript 编译器对文件名的大小写一致性进行强制检查
这个选项的主要目的是确保在不同的操作系统和文件系统上使用 TypeScript 时,文件名的大小写一致性,从而减少由于文件名大小写不一致引起的问题
不推荐关闭这个选项, 如果开发人员 A 在区分大小写的文件系统中工作而开发人员 B 则在不区分大小写的文件系统中工作,这可能出现问题
isolatedModules
tsc 在编译时, 可以依赖这个项目的所有文件,正确的分辨出import
语句中,哪些是type value
哪些是pure value
, 而 babel 或者其他编译器在通过 ts-api 编译文件时, 只能分析单个文件, 所以这些编译器导出的编译文件可能会在运行时出现问题
该选项设置为true
时, ts 会在发现文件包含一些在单一文件编译过程中可能导致运行错误的代码时, 给出警告
比如:
typescript
// foo.ts
export interface User {
name: string;
}
// main.ts
import { User } from "./foo";
export { User }; // Error: Re-exporting a type when 'isolatedModules' is enabled requires using 'export type'.
// 正确的写法是
import { type User } from "./foo";
export { User };
// 或者
import { User } from "./foo";
export type { User };
开启这个选项的主要目的还是规范代码, 该有的标记一个都不能少, 该添加
type
修饰符的就加上去, 避免 babel 或其他编译器处理 ts 文件时产生无法预知的错误
preserveSymlinks
用于控制在编译 TypeScript 代码时是否保留符号链接(symlinks)的原始结构。符号链接是一种文件系统中的特殊文件类型,它可以引用其他文件或目录。这个选项有两个可能的值:
true
:表示保留符号链接的原始结构。当设置为 true
时,TypeScript 编译器会在编译过程中保持符号链接的原始路径和结构不变。
false
(默认值):表示不保留符号链接的原始结构。当设置为 false 时,TypeScript 编译器会解析符号链接并使用它们的目标文件或目录进行编译。
如果项目中使用了符号链接,并且希望在编译过程中保留符号链接的原始结构以及相对路径信息,可以将 preserveSymlinks 设置为 true
如果项目中使用符号链接,但更关心符号链接的目标文件而不是原始结构,或者如果开发环境不依赖于符号链接的原始结构,那么使用默认值 false
可能更合适。
另一种情况是,如果在 Windows 操作系统上开发,由于 Windows 对符号链接的支持较有限,可能更倾向于使用 false
,因为在 Windows 上编译时,true
可能会导致一些问题。
verbatimModuleSyntax
ts@5 版本引入的新选项, 用来简化importsNotUsedAsValues
,preserveValueImports
等两个选项
当设为true
的时候, 任何import
和export
中没有type
修饰符的代码都会被保留下来, 带有type
修饰符的都会被完全删除
typescript
// 编译前
import foo from "foo";
export const age = 1;
// 设置为false 编译后, // foo未被使用, 会被移除
export var age = 1;
// 设置为true 编译后
import foo from "foo";
export var age = 1;
再比如:
typescript
// 编译前
import { type User } from "./foo"; // 这句也会被移除, 因为User只在ts中有效
export function init(user: User) {
console.log("init");
}
// 设置为false 编译后
export function init(user) {
console.log("init");
}
// 设置为true 编译后
import {} from "./foo";
export function init(user) {
console.log("init");
}
需要注意的是, 如果项目编译目的设置为任何使用require
或者module.exports
的代码, verbatimModuleSyntax
不要 设置为true
, 否则 ts 会在编译过程中抛出错误
Backwards Compatibility 向后兼容相关选项
charset (deprecated)
在早期的 ts 版本中, 这个选项用来控制 ts 读取文件时所使用的编码, 现在默认值就是utf-8
; 不需要另行配置
keyofStringsOnly (deprecated)
该选项已被弃用, 现在默认是 true 了
keyof
是 ts 中的一个操作符: 假设有这么一段代码:
typescript
export interface Person {
name: string;
age: number;
address: string;
[key: string]: unknown;
}
export type PersonKeys = keyof Person;
let t: PersonKeys = "name";
t = "age";
t = "address";
t = 2;
该选项设置为false
时, 上面的代码是不会报错的, 因为export type PersonKeys = keyof Person;
就相当于 type PersonKeys="name" | "age" | "address" | string | number
如果选项设置为true
, t=2
会抛出错误, 因为此时export type PersonKeys = keyof Person;
就相当于 type PersonKeys="name" | "age" | "address"
noImplicitUseStrict (deprecated)
默认情况下, ts 在module
选项设置为非 ES 时,会自动在输出文件头部添加use strict
, 启用该选项会禁止这个行为
noStrictGenericChecks (deprecated)
假设有以下代码:
typescript
type A = <T, U>(x: T, y: U) => [T, U];
type B = <S>(x: S, y: S) => [S, S];
function f(a: A, b: B) {
b = a; // Ok
a = b; // Error
}
默认情况下, ts 会提示如下错误信息, 因为把b
赋值给a
的时候, ts 会校验这两者的类型信息, 函数类型B
的泛型参数明显少于A
的参数, ts 默认是不允许此类行为的:
python
Type 'B' is not assignable to type 'A'.
Types of parameters 'y' and 'y' are incompatible.
Type 'U' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'U'.
该选项设置为true
, ts 将不再校验此类行为
out
suppressExcessPropertyErrors (deprecated)
该选项用来控制 ts 在检测到多余属性时是否报告异常
比如以下代码:
typescript
const person: { name: string } = { name: "Alice", age: 30 };
这里面的age
属性, 不在预定义的类型声明中, 默认情况下 ts 会报告异常
如果该选项设置为true
, ts 不会报告此类异常
suppressImplicitAnyIndexErrors (deprecated)
该选项用来控制 ts 在检测到隐式 any时是否报告异常
比如以下代码:
typescript
const obj = {
name: "Alice",
age: 30,
};
const prop = obj["address"]; // TypeScript 会发出类型错误
这里 ts 无法确定address
的类型, 默认情况下 ts 会报告异常
如果该选项设置为true
, ts 不会报告此类异常
该选项在新版本中可以使用noImplicitAny
选项代替
extendedDiagnostics 编译分析相关选项
extendedDiagnostics
使用 extendedDiagnostics
编译选项,TypeScript 编译器会生成额外的详细诊断信息,更容易地定位和解决潜在的问题。
这个选项对于识别潜在问题、优化代码和进行代码审查非常有用。它提供了比默认诊断更多的信息,以便开发人员更好地理解其代码。
下面是该选项设为true
后, 控制台的输出信息:
shell
~/Documents/office/aprojects/zhongke/vary-ui/ts/ npx tsc
Files: 156
Lines of Library: 38131
Lines of Definitions: 84722
Lines of TypeScript: 2
Lines of JavaScript: 0
Lines of JSON: 0
Lines of Other: 0
Identifiers: 126583
Symbols: 241069
Types: 67264
Instantiations: 170459
Memory used: 284856K
Assignability cache size: 22613
Identity cache size: 169
Subtype cache size: 0
Strict subtype cache size: 0
I/O Read time: 0.12s
Parse time: 0.65s
ResolveTypeReference time: 0.01s
ResolveModule time: 0.02s
ResolveLibrary time: 0.03s
Program time: 0.88s
Bind time: 0.26s
Check time: 2.32s
transformTime time: 0.01s
commentTime time: 0.00s
I/O Write time: 0.01s
printTime time: 0.03s
Emit time: 0.03s
Total time: 3.49s
diagnostics
该选项是extendedDiagnostics
选项的子集, 也会生成额外的详细诊断信息; 但它的输出信息少一些
下面是该选项设置为true
时编译后的输出信息:
shell
~/Documents/office/aprojects/zhongke/vary-ui/ts/ npx tsc
Files: 156
Lines: 122855
Identifiers: 126583
Symbols: 241069
Types: 67264
Instantiations: 170459
Memory used: 279910K
I/O read: 0.03s
I/O write: 0.00s
Parse time: 0.73s
Bind time: 0.23s
Check time: 1.95s
Emit time: 0.02s
Total time: 2.93s
traceResolution
这个选项设为true
时, ts 会在编译过程中将输出有关模块解析的详细信息,包括 TypeScript 编译器在哪里找到了每个模块以及模块之间的依赖关系
explainFiles
这个选项设为true
时, ts 会在编译过程中将输出有关模块解析和文件查找的详细信息,提供更为详细和全面的信息,适用于复杂的模块解析和依赖问题的诊断
generateCpuProfile
该选项只能通过 CLI 的方式使用
该选项用来告诉 ts 在编译完成后, 输出一份文件, 该文件内保存了本次编译过程中所有处理步骤在 cpu 中占用的时间, 主要目的是帮助开发人员分析构建速度缓慢的原因
shell
# 使用方法
npm run tsc --generateCpuProfile tsc-output.cpuprofile
listFiles
该选项用来控制 ts 在构建过程中所有使用的.d.ts
文件
如果 ts 抛出一些类似于未找到xxx的声明文件
等错误, 或者想知道 ts 到底使用了哪些.d.ts
文件时, 可以启用该选项
下面是输出案例:
shell
~/Documents/office/aprojects/zhongke/vary-ui/ts/ npx tsc
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es5.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2015.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2016.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2017.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2018.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2019.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2020.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.dom.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.webworker.importscripts.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.scripthost.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2015.core.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2015.collection.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2015.generator.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2015.iterable.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2015.promise.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2015.proxy.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2015.reflect.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2015.symbol.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2016.array.include.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2017.date.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2017.object.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2017.string.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2017.intl.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2018.intl.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2018.promise.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2018.regexp.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2019.array.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2019.object.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2019.string.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2019.symbol.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2019.intl.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2020.bigint.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2020.date.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2020.promise.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2020.string.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2020.intl.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.es2020.number.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.esnext.intl.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.decorators.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/node_modules/typescript/lib/lib.decorators.legacy.d.ts
/Users/loki/Documents/office/aprojects/zhongke/vary-ui/ts/main.ts
...
listEmittedFiles
该选项用来控制 ts 在构建完成后输出所有的编译后文件列表
这个列表中包含了:
.js
.js.map
.d.ts
.d.ts.map
Output Formatting 输出相格式化关选项
noErrorTruncation
当错误信息过长, ts 会自动截取一部分错误消息
把该选项设为true
, 会阻止 ts 的截取操作, 强制 ts 展示完整的错误信息(这个选项在 VSC 编辑器中也同样有效), 比如下面的案例:
typescript
var x: {
propertyWithAnExceedinglyLongName1: string;
propertyWithAnExceedinglyLongName2: string;
propertyWithAnExceedinglyLongName3: string;
propertyWithAnExceedinglyLongName4: string;
propertyWithAnExceedinglyLongName5: string;
propertyWithAnExceedinglyLongName6: string;
propertyWithAnExceedinglyLongName7: string;
propertyWithAnExceedinglyLongName8: string;
};
// String representation of type of 'x' should be truncated in error message
var s: string = x;
默认提示:
shell
~/Documents/office/aprojects/zhongke/vary-ui/ts/ npx tsc
main.ts:13:5 - error TS2322: Type '{ propertyWithAnExceedinglyLongName1: string; \
propertyWithAnExceedinglyLongName2: string; propertyWithAnExceedinglyLongName3: string; \
propertyWithAnExceedinglyLongName4: string; propertyWithAnExceedinglyLongName5: string; \
propertyWithAnExceedinglyLongName6: string; propertyWithAnExceedinglyLongName7: string; \
propert...' is not assignable to type 'string'.
13 var s: string = x;
~
Found 1 error in main.ts:13
设置为true
后:
shell
~/Documents/office/aprojects/zhongke/vary-ui/ts/ npx tsc
main.ts:13:5 - error TS2322: Type '{ propertyWithAnExceedinglyLongName1: string; \
propertyWithAnExceedinglyLongName2: string; propertyWithAnExceedinglyLongName3: string; \
propertyWithAnExceedinglyLongName4: string; propertyWithAnExceedinglyLongName5: string; \
propertyWithAnExceedinglyLongName6: string; propertyWithAnExceedinglyLongName7: string; \
propertyWithAnExceedinglyLongName8: string; }' is not assignable to type 'string'.
13 var s: string = x;
~
Found 1 error in main.ts:13
preserveWatchOutput
这个选项用于配置 TypeScript 编译器在监视模式下的行为。具体来说,preserveWatchOutput 有两个可能的值:
如果将 preserveWatchOutput
设置为 true
(默认值),TypeScript 编译器会尽量保留输出文件,以便在发生错误时提供更多信息。这意味着即使有错误,也会生成输出文件,以便你可以查看部分编译结果,并更容易进行故障排除。这对于大型项目的快速迭代和调试非常有用。
如果将 preserveWatchOutput
设置为 false
,TypeScript 编译器将在发现错误时删除输出文件,以确保输出始终保持与源代码同步。这对于在每次编译时都要求输出文件保持一致的情况很有用。
在大多数情况下,将 preserveWatchOutput
保持为默认值(true
)是合适的,因为它有助于更好地理解错误并进行快速调试
pretty
该选项用于配置 ts 输出日志的时候使用带颜色文本, 默认值是true
Completeness 完整性配置选项
skipDefaultLibCheck
已弃用, 使用skipLibCheck
选项代替
skipLibCheck
它用于控制 TypeScript 编译器是否要跳过对声明文件(.d.ts
文件)的类型检查。这个选项的默认值是 false
。
具体来说,skipLibCheck
有以下两个可能的值:
如果将 skipLibCheck
设置为 true
,TypeScript 编译器将跳过对声明文件的类型检查。这意味着编译过程不会检查 .d.ts 文件中的类型错误。这在一些情况下可能会加快编译速度,尤其是在处理大型项目时。
如果将 skipLibCheck
设置为 false
(默认值),TypeScript 编译器会执行对声明文件的类型检查,以确保它们的类型与实际代码的类型兼容。这对于类型安全和代码质量很重要,但可能会导致较长的编译时间。
在大多数情况下,将 skipLibCheck
保持为默认值(false
)是合适的,因为它有助于确保你的代码与声明文件保持一致,从而减少潜在的类型错误。然而,在某些情况下,如果你确定你的声明文件是正确的,你可以将 skipLibCheck
设置为 true
以提高编译性能。
Watch Options 监视模式相关选项
该选项建议保持默认设置
ts 支持多种不同的方法跟踪文件与目录的变化, 不同的项目中, 每种方法的工作效率可能不一样, 所以 ts@3.8 版本开始引入了这个选项, 允许用户自行定义监视过程与方法
这写配置项一般写在watchOptions
中
javascript
{
"watchOptions":{
// Use native file system events for files and directories
"watchFile": "useFsEvents",
"watchDirectory": "useFsEvents",
// Poll files for updates more frequently
// when they're updated a lot.
"fallbackPolling": "dynamicPriority",
// Don't coalesce watch notification
"synchronousWatchDirectory": true,
// Finally, two additional settings for reducing the amount of possible
// files to track work from these directories
"excludeDirectories": ["**/node_modules", "_build"],
"excludeFiles": ["build/fileWhichChangesOften.ts"]
}
}
watchFile
有以下可用值:
fixedPollingInterval
:以固定的时间间隔每秒多次检查每个文件是否有更改。
priorityPollingInterval
:每秒多次检查每个文件是否有更改,但使用启发式方法检查某些类型的文件的频率低于其他文件的频率。
dynamicPriorityPolling
:使用动态队列,其中不经常修改的文件将被较少检查。
useFsEvents
(默认值):尝试使用操作系统/文件系统的本机事件进行文件更改。
useFsEventsOnParentDirectory
:尝试使用操作系统/文件系统的本机事件来侦听文件父目录的更改
watchDirectory
在缺乏递归文件监视功能的系统下如何监视整个目录树的策略。
fixedPollingInterval
:以固定的时间间隔每秒多次检查每个目录是否有更改。
dynamicPriorityPolling
:使用动态队列,其中不经常修改的目录将被较少检查。
useFsEvents
(默认值):尝试使用操作系统/文件系统的本机事件进行目录更改。
fallbackPolling
使用文件系统事件时,此选项指定当系统用完本机文件观察程序和/或不支持本机文件观察程序时使用的轮询策略。
fixedPollingInterval
:以固定的时间间隔每秒多次检查每个文件是否有更改。
priorityPollingInterval
:每秒多次检查每个文件是否有更改,但使用启发式方法检查某些类型的文件的频率低于其他文件的频率。
dynamicPriorityPolling
:使用动态队列,其中不经常修改的文件将被较少检查。
synchronousWatchDirectory
:禁用目录上的延迟监视。当可能同时发生大量文件更改时(例如,运行 npm install 时 node_modules 发生更改),延迟监视非常有用,但对于一些不太常见的设置,您可能希望使用此标志禁用它。
excludeFiles
停止 ts 监控某些指定文件的变动
javascript
{
"watchOptions": {
"excludeFiles": ["temp/file.ts"]
}
}
excludeDirectories
停止 ts 监控某些指定目录的变动
javascript
{
"watchOptions": {
"excludeDirectories": ["**/node_modules", "_build", "temp/*"]
}
}