- include, exclude, files配置项
- extends配置
- compilerOptions下的配置
- compilerOptions.allowUnreachableCode
- compilerOptions.allowUnusedLabels
- compilerOptions.alwaysStrict
- compilerOptions.exactOptionalProperties
- compilerOptions.downlevelIteration
- compilerOptions.importHelpers
- compilerOptions.strict
- compilerOptions.strictBindCallApply
- compilerOptions.strictFunctionTypes
- compilerOptions.strictNullChecks
- compilerOptions.strictPropertyInitialization
- compilerOptions.noImplicitAny
- compilerOptions.noImplicitOverride
- compilerOptions.noImplicitReturns
- compilerOptions.noImplicitThis
- compilerOptions.noPropertyAccessFromIndexSignature
- compilerOptions.noUncheckedIndexedAccess
- compilerOptions.noUnusedLocals
- compilerOptions.noUnusedParameters
- compilerOptions.useUnknownInCatchVariables
- 小结
- 我对typescript一些看法
基于typescript的项目的根目录下都会有一个文件(tsconfig.json
), 这个文件主要用来控制typescript编译器(tsc, typescript compiler)的一些行为, 比如指定哪些文件需要让tsc来编译, 哪些文件不想让tsc进行编译之类的.
angular项目的tsconfig.json
文件
tsconfig.json
/* To learn more about this file see: https://angular.io/config/tsconfig. */{ \"compileOnSave\": false, \"compilerOptions\": { \"baseUrl\": \"./\", \"outDir\": \"./dist/out-tsc\", \"sourceMap\": true, \"declaration\": false, \"downlevelIteration\": true, \"experimentalDecorators\": true, \"moduleResolution\": \"node\", \"importHelpers\": true, \"target\": \"es2015\", \"module\": \"es2020\", \"lib\": [ \"es2018\", \"dom\" ] }, \"angularCompilerOptions\": { \"enableI18nLegacyMessageIdFormat\": false, \"strictTemplates\": true }}
这其中angularCompilerOptions
顾名思义是angular专用的, 不在本文讨论范围.
include, exclude, files配置项
include
: 指定要编译哪些文件, 比如只需要编译<project-dir>/src
目录下的.ts源代码文件
{ \"compilerOptions\": { ... }, include: [\"./src/**/*\", \"./demo/**/*.tsx?\"]}
上面的include配置用到了两个通配符: **/
, *
**/
表示匹配任何子路径, 包括目录分隔符/
也会被它匹配, 所以用来这个通配符后, 目录下有多少子目录都会被匹配到
*
表示匹配除了目录分隔符(/
)外的任何长度的字符串
?
表示匹配一个除文件分隔符(/
)外的任一字符
显然./src/**/*
即表示匹配src
文件夹下的任何子文件夹的任何文件; 而./demo/**/*.tsx?
即表示匹配demo
目录下任何子目录下的任意以.ts
或.tsx
结尾的文件
include其实就是一个白名单, 在这个白名单里被匹配到的文件才会被tsc处理编译
相对于include
是作为白名单的配置, exclude
选项就是一个黑名单了, 它的值和include一样是一个路径名字符串数组, 最常见的用处就是用来排除掉node_modules
目录下的文件
{ \"compilerOptions\": { ... }, include: [\"./src/**/*\", \"./demo/**/*.tsx?\"], exclude: [\"node_modules/**/*\"]}
当然也可以用exclude
排除掉include
里面包含到的文件
有些情况即使exclude了某些文件后, 编译后的代码中可能仍然包含被
exclude
了的内容, 比如通过import
导入了被exclude
了的node_modules
文件夹, 此时tsc仍然会去处理被exclude了的文件, 这一点应该不难理解
files
配置的作用类似include
, 也是一个白名单路径数组, 不同在于它不能使用通配符, 而必须使用精确的文件路径(可以是相对路径), 比如如果项目只有一个入口文件, 那么就可以使用在只用files
配置这个文件的路径, 然后其他的文件都通过index.ts
来import
tsconfig.json
{ \"compilerOptions\": { ... }, // include: [\"./src/**/*\", \"./demo/**/*.tsx?\"], // exclude: [\"node_modules/**/*\"] files: [\'./src/index.ts\']}
extends配置
extends
用于在一个tsconfig.json
文件中扩展其他tsconfig.json
文件, 比如angular项目中有三个tsconfig配置文件: tsconfig.json
, tsconfig.spec.json
, tsconfig.app.json
tsconfig.json
/* To learn more about this file see: https://angular.io/config/tsconfig. */{ \"compileOnSave\": false, \"compilerOptions\": { \"baseUrl\": \"./\", \"outDir\": \"./dist/out-tsc\", \"sourceMap\": true, \"declaration\": false, \"downlevelIteration\": true, \"experimentalDecorators\": true, \"moduleResolution\": \"node\", \"importHelpers\": true, \"target\": \"es2015\", \"module\": \"es2020\", \"lib\": [ \"es2018\", \"dom\" ] }, ...}
tsconfig.app.json
{ \"extends\": \"./tsconfig.json\", \"compilerOptions\": { \"outDir\": \"./out-tsc/app\", \"types\": [] }, \"files\": [ \"src/main.ts\", \"src/polyfills.ts\" ], \"include\": [ \"src/**/*.d.ts\" ]}
tsconfig.spec.json
/* To learn more about this file see: https://angular.io/config/tsconfig. */{ \"extends\": \"./tsconfig.json\", ... \"files\": [ \"src/test.ts\", \"src/polyfills.ts\" ], \"include\": [ \"src/**/*.spec.ts\", \"src/**/*.d.ts\" ]}
从命名和文件内容上即可看出之所以这么做是为了针对测试文件.spec.ts
和普通.ts
文件在使用不同的配置时又能共享他们相同部分的配置, 达到避免重复的目的
compilerOptions下的配置
compilerOptions.allowUnreachableCode
表示是否允许代码中出现永远无法被执行到的代码, 可选值是undefined
, false
, true
{ \"compilerOptions\": { \"allowUnreachableCode\": false ... }, ...}
什么是\”永远无法被执行到的代码\”?
const foo = () => { return 0; console.log(\'aaa\'); // 这一行代码就是永远被执行到的代码}
配置为undefined
时, 遇到这种情况会给出warning, 配置false则直接编译时抛出错误无法成功编译, 配置为true既没有警告也没有错误
compilerOptions.allowUnusedLabels
这个选项是针对标签(label)语法的, 这个语法很罕见, 我也是看到了这个配置才知道有这个原来js还有Label
语法, label语法有点像其他语言里的goto, 真是场景中几乎不用
compilerOptions.allowUnusedLabels
表示是否允许未使用到的标签
可选项:
undefined
: 这是默认值, 碰到未使用的标签给出warning警告false
: 碰到未使用的标签抛出错误, 编译失败true
: 碰到未使用的标签编译通过, 且不给出异常
function bar() { console.log(\'loafing...\'); loop: for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (i === 2) { // break loop; } console.log(i, j, i + j); } }}
compilerOptions.alwaysStrict
默认值是true
, 开启这个选项保证输出的js代码处于ECMAScript标准的严格模式下, 也就是js文件里的use strict
compilerOptions.exactOptionalProperties
这是typescript4.4中才加入的一个选项, 默认处于不开启状态; 开启此选项, typescript会对可空属性执行更严格的类型检查, 可空属性只有在初始化时可以留空为undefined
, 但是不能被手动设置为undefined
例如有一个IFoo
接口
interface IFoo { foo?: string;}
在compilerOptions.exactOptionalProperties = false
情况下
const obj: IFoo = {};obj.foo = \'1111\';console.log(obj.foo);obj.foo = undefined;console.log(obj.foo);
这段代码可以正常编译通过
但如果开启compilerOptions.exactOptionalProperties
选项后情况就不同了
const obj: IFoo = {};obj.foo = \'1111\';console.log(obj.foo);// 编译器会报: Type \'undefined\' is not assignable to type \'string\' with \'exactOptionalPropertyTypes: true\'. Consider adding \'undefined\' to the type of the target.obj.foo = undefined;console.log(obj.foo);// 这一行会报: Type \'{ foo: undefined; }\' is not assignable to type \'IFoo\' with \'exactOptionalPropertyTypes: true\'. const obj2: IFoo = { foo: undefined}
compilerOptions.downlevelIteration
先解释下什么是Downleveling
? Downleveling
是Typescript中的一个术语, 它表示将typescript代码转译为相对更低版本的javascript
这个标志位模式是不开启的.
开启这个标志位typescript会生成一个帮助方法来对es6中的for of
和数组展开([...arr]
)语法进行转译, 以兼容es3/es5
下面的示例用for of
循环并输出一个包含符号表情的字符串:
const text = `(