TypeScript – tsconfig
<h2>前言</h2><p>上一篇 TypeScript – Get Started 使用了命令</p>
<div class="cnblogs_code">
<pre>tsc index.ts --module es2015</pre>
</div>
<p>很少人会在命令时给写 config, 更正规的做法是创建一个 tsconfig.json 把所有 config 写到里面去. 类似 webpack.config.js, tailwind.config.js, .eslintrc.json, prettier.config.js, stylelint.config.js</p>
<p> </p>
<h2>参考</h2>
<p>详解tsconfig.json文件 (must read)</p>
<p> </p>
<h2>Create tsconfig.json</h2>
<div class="cnblogs_code">
<pre>tsc --init</pre>
</div>
<p>运行命令后就会创建出 tsconfig.json 了</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202204/641294-20220428224518528-408831223.png"></p>
<p>里面包含了所有 config 和 注释. 有需要的就开启.</p>
<p> </p>
<h2>常用 Config</h2>
<h3>1. target</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"target": "es2016"<span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<p>target 指的是 TypeScript transpile 出来想要生成什么 version 的 ECMAScript</p>
<p>ES3 已经完全没有人用了, ES5 应该是目前最低的配置了.</p>
<p>tsconfig 的 默认是生成 ES2016 也就是 ES7. 毕竟很少人要支持 Internet Explorer 了.</p>
<p>Angular 默认是生成 ES2017.</p>
<p> </p>
<h3>2. lib</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"target": "ES2016"<span style="color: rgba(0, 0, 0, 1)">,
</span>"lib": ["DOM", "ES2016", "ES2017.Object"<span style="color: rgba(0, 0, 0, 1)">],
}</span></pre>
</div>
<p>lib 和 target 通常是一套的. 它指的是在开发阶段, TypeScript 对应的 ECMAScript version.</p>
<p>我举个具体的例子你就明白了. 假设项目需要支持比较旧的游览器, 那个游览器只支持 ES2016, 那么 target 就 set 成 ES2016 咯.</p>
<p>但是呢, 开发人员又很想用 ES2017 的某个功能, 比如 Object.values. 那怎么办? 要让游览器支持 Object.values 可以通过 polyfill (比如引入 core.js)</p>
<p>但是在开发阶段, TypeScript 不知道你有 polyfill, 所以如果你写 Object.values 它就报错提示你 (因为你 target ES2016 不能超过这个功能范围). 所以 lib 就排上用场了.</p>
<p>lib 就是让你声明开发阶段, 你的 ECMAScript version. </p>
<p>"DOM" 声明, 这个 TypeScript 用于游览器, 所以可以调用 document, window 这类接口</p>
<p>"ES2016" 声明, TypeScript 能写到 ES2016 的语法和各种 build-in 方法</p>
<p>"ES2017.Object" 声明, TypeScript 还能写到 ES2017 Object 的 build-in 方法 (比如 Object.values).</p>
<p>所以 target, lib, polyfill 的玩法就是这样啦.</p>
<p>注: lib 如果没有声明它, 那么它会依据不同的 target 设定 default 的 lib, 一旦声明了它就是完全 override 掉 default 的.</p>
<h3>How to enable Internet Explorer on Windows 11</h3>
<p>我为了做测试特地学了如何在 Windows 11 开启 Internel Explorer, 这里做个记入呗, 参考: Youtube – How to enable Internet Explorer on Windows 11</p>
<p>打开 edge 游览器 > 右上角 ... 打开选择 setting > 左边选 default browser > 然后 allow sites > add 要测试的页面.</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202207/641294-20220711235343170-1339928199.png"></p>
<p>接着打开测试页面就可以了.</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202207/641294-20220711235532918-2029694401.png"></p>
<p><strong>更新: 2 Jun 2022</strong></p>
<p>目前 standard 的 target 是 es2017, 经常遇到 Array.flatMap 无法使用的烦恼. 那么可以这样配置</p>
<div class="cnblogs_code">
<pre>"target": "es2017"<span style="color: rgba(0, 0, 0, 1)">,
</span>"lib"<span style="color: rgba(0, 0, 0, 1)">: [
</span>"DOM", "DOM.Iterable", "ES2017", "ES2019.Array"<span style="color: rgba(0, 0, 0, 1)">
],</span></pre>
</div>
<p>注: DOM.Iterable 是必须的哦, 不然就会出现如下错误</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202206/641294-20220602185725622-477331333.png"></p>
<p> </p>
<h3>3. files, include, exclude</h3>
<p>这 3 属性都是用来设定 .ts files 扫描范围的</p>
<p>默认情况下, tsconfig sibling 和 descendant 的 .ts 都会被 transpile to .js</p>
<p>例子说明:</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220501192227446-1044925651.png"></p>
<p>注: 它不是 complilerOptions 的属性哦, 是最外面对象的属性</p>
<p>这是 files 结构</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220501192359258-1920663145.png"></p>
<p>files 只能指定具体的 file 不能写 glob</p>
<p>include 和 exclude 则可以写 glob</p>
<p>通常设置的方式是这样的, include 你要的大范围, files 一些例外 (out of inclde 范围的), exclude 一些例外 (在 include 范围内的)</p>
<p> </p>
<h3>4. outDir & rootDir</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"rootDir": "./src"<span style="color: rgba(0, 0, 0, 1)">,
</span>"outDir": "./dist"<span style="color: rgba(0, 0, 0, 1)">,
}</span></pre>
</div>
<p>rootDir 我也不清楚什么时候会用到, outDir 就是指 transpile 后的 .js 要 output 到哪里. 默认情况下是 output 到 .ts 的 sibling.</p>
<p>配置成 ./dist 以后, 它就会创建一个 dist folder, 然后依据 .ts 结构 output 到 dist 里面.</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220501195320279-814889093.png"></p>
<p> </p>
<h3>5. removeComments</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"removeComments": <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
}</span></pre>
</div>
<p>顾名思义, 就是把 .ts 里面的 comment 在 transpile 过程中移除. .js file 里面就看不到任何 comment 了</p>
<p> </p>
<h3>6. sourceMap, inlineSourceMap</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"sourceMap": <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
}</span></pre>
</div>
<p>transpile 的 JavaScript 阅读非常不友好, runtime debug 就会很困难. 开启 sourceMap compiler 就会创建一个 .map 的 file</p>
<p>这样 chrome dev tool / debuger 就可以找到 erorr 在 .ts 源文件的位置. 开发阶段必开.</p>
<p>p.s: inlineSourceMap 就是它会把 mapping 放入 .js 文件, 而不是创建都都一个 .map 的 file.</p>
<p> </p>
<h3>7. module</h3>
<p>JavaScript 的 modular 是出了名的混乱. 可以看这篇 JavaScript – Modular.</p>
<p>JavaScript 又可以用于前端 Browser 和后端 Node.js. 所以 TypeScript 需要兼顾到这些.</p>
<p>如果是 for Node.js 那么 module 的值是 <strong>"CommonJS"</strong> 或者 <strong>"ES2020".</strong></p>
<p>如果是 for Browser 而且有使用 module bundler (e.g. Webpack), 那么 module 设置成 <strong>"ES2020" </strong>就可以了, bunlder 会处理好一切. (像 Angular 那样)</p>
<p>如果没有使用 module bundler, 设置 <strong>"ES2020" </strong>就表示完全使用游览器的 ES Module. 通常不是一个好主意. 现阶段最好还是使用 SystemJS 或者 RequireJS 来管理前端模块 (不然会需要加载很多 js files)</p>
<p>一个折中的方案是用 TypeScript Compiler 的 bundler 配上 SystemJS 或 RequireJS. module 设置成 <strong>"AMD"</strong> 或者 <strong>"System". </strong>看这篇</p>
<p>example:</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220501204317048-418985295.png"></p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220501204321855-701563469.png"></p>
<p> <img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220501204330615-515305551.png"></p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220501204334168-1806026468.png"></p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220501204337381-504911190.png"></p>
<p> </p>
<h3>8. moduleResolution</h3>
<p>它有 2 个值, <strong>"Classic"</strong> 和 <strong>"Node". </strong>默认是 Classic, 但凡你有用 node_modules 就设置成 Node 就对了.</p>
<p>它指的是当我们写 import {} from 'xxx' 的时候, TypeScript Compiler 怎么去找到这个 module.</p>
<p>想具体了解的话建议看这篇: 深入理解TypeScript的模块系统, 讲的比较清楚.</p>
<p>我自己的测试是, 如果 "module": "ES2020", 那么不设置 "moduleResolution": "node" 会报错</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202206/641294-20220602235028956-120934701.png"></p>
<p>如果 "module": "CommonJS" 就不会报错. 这个是 esbuild 的测试场景.</p>
<p>v5.0 后多了一个值 "<strong>Bundler</strong>",bundler 是 for Vite、Webpack 这些的。</p>
<p>用了 Bundler 以后 allowSyntheticDefaultImports: true 就不需要了,这个本来是 for import DefaultModule from 'module' 用的。</p>
<p> </p>
<h3>9. outFile</h3>
<p>上面有提到 TypeScript bundler, 它只是一个简单 for 单元测试的工具, TypeScript 的职责是 transpile 不是 bundle. </p>
<p>bundle 还是用 Webpack 之类的比较好.</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"module": "System"<span style="color: rgba(0, 0, 0, 1)">,
</span>"outFile": "./dist/bundle.js"<span style="color: rgba(0, 0, 0, 1)">,
}</span></pre>
</div>
<p>设置 outFile 以后, 最后只会生成一个 bundle.js 所有代码都在里头. 必须配上 SystemJS 或者 RequireJS 才能发挥功效哦.</p>
<p> </p>
<h3>10. declaration, declarationDir</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"declaration": <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<p>TypeScript transpile 除了生成 .js 还可以生成 .d.ts 类型文件.</p>
<p>这个对 Library 发布就很重要, 因为有了 .d.ts, 那些使用 Library 开发者即使没有用 TypeScript 也可以通过 VS Code 得到很多类型的提示.</p>
<p> </p>
<h3>11. allowJs, checkJs</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"allowJs": <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
</span>"checkJs": <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
}</span></pre>
</div>
<p>TypeScript 默认配置是不允许 import js 的, 如果想 import js 文件那么需要在 tsconfig 设置 allowJs</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220502101432491-1266610640.png"></p>
<p>JavaScript 是没有类型检查的, 但如果你想让它带有一点类型检查, 但又不要像 TypeScript 那么 "类型", 可以开启 checkJs</p>
<p>这个功能和 VS Code 的 Working with JavaScript 是一样的</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220502101840984-762968561.png"></p>
<p>// @ts-check, // @ts-ignore // @ts-nocheck 配上 checkJs 一同使用</p>
<p>使用注释来声明类型</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220502102037131-679929808.png"></p>
<p>p.s. 不推荐使用 allowJs, 比较好的做法是提供 .d.ts 文件</p>
<p> </p>
<h3>12. typeRoots, types</h3>
<p>当使用没有类型的 JavaScript Library 时, 需要提供 .d.ts Type Declarations.</p>
<p>大部分第三方 Library 的 .d.ts 都可以到 npm 下载, 下载后会被收入到 node_modules/@types 里面.</p>
<p>但如果没有在 npm 找到. 那就需要我们自己编写 .d.ts.</p>
<p>then 这个文件不可能放到 node_modules 嘛, 所以得在外面开一个 types folders</p>
<p>我们需要让 TypeScript compiler 知道这个 folder, 所以需要在 tsconfig.json 添加上 typeRoots</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"compilerOptions"<span style="color: rgba(0, 0, 0, 1)">: {
</span>"typeRoots": ["./node_modules/@types", "./types"<span style="color: rgba(0, 0, 0, 1)">],
</span>"types": ["jquery", "my-library"<span style="color: rgba(0, 0, 0, 1)">]
}
}</span></pre>
</div>
<p>override typesRoots 必须把 node_modules/@types 补回去哦</p>
<p>types 做用是进一步 filter, 在 typeRoots folder 里, 只有 jquery 和 my-library 被纳入, 其它无视.</p>
<p>注: 虽然上面理论是这样说, 但在开发的时候, 我发现不管我 .d.ts 放哪里都是可以找到类型的..懒得去研究, 等以后看看有没有问题呗</p>
<p> </p>
<h3>13. paths</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"paths"<span style="color: rgba(0, 0, 0, 1)">: {
</span>"local-library": ["./local-library/local-library"<span style="color: rgba(0, 0, 0, 1)">],
</span>"local-library/*": ["./local-library/*"<span style="color: rgba(0, 0, 0, 1)">],
},
}</span></pre>
</div>
<p>这个常用在本地 Library. </p>
<p>当配置好 paths 以后, import 的时候就不走 relative path 了, 反而是像 import node_modules 的 module 那样, 直接写名字</p>
<div class="cnblogs_code">
<pre>import { localLibraryFunction } from 'local-library'<span style="color: rgba(0, 0, 0, 1)">;
import { abc } from </span>'local-library/abc';</pre>
</div>
<p>这些名字就会去 tsconfig paths 做匹配, 然后去寻找 .ts 文件. 它就是这样串起来用的. </p>
<p> </p>
<h3>14. experimentalDecorators</h3>
<p>参考: angular2 学习笔记 (Typescript - Attribute & reflection & decorator)</p>
<p><img src="https://img2022.cnblogs.com/blog/641294/202205/641294-20220503160413436-1930298726.png"></p>
<p>想做到类似 C# 那种 Data Annotation Validation, 反射, 就需要借助 TypeScript 的 Decorators 功能.</p>
<p> </p>
<h3>15. downlevelIteration</h3>
<p>参考: Downlevel Iteration - downlevelIteration </p>
<p>这个是针对 target: es5, 使用 for of 的时候它会编辑成什么格式. Angular 的 tsconfig 有开启, 所以我这里提一下. </p>
<p> </p>
<h3>17. importHelpers</h3>
<p>参考: Import Helpers - importHelpers</p>
<p>有些代码被 compile 之后会很长, 比如 downlevelIteration, extending class, spreading arrays or objects, and async operations</p>
<p>开启 importHelpers, 它会 import from 'tslib' 把它们封装起来. 可以节省代码量. 随着 target 越来越高, downlevelIteration 和 importHelpers 以后应该是不需要的了.</p>
<p>目前 Angular tsconfig 也是有开启的. 另外如果你想提供自己的 'tslib' 可以开启 noEmitHelpers.</p>
<p> </p>
<h3>18. noUncheckedIndexedAccess</h3>
<p>参考: Youtube – TypeScript option you want to enable beyond strict : noUncheckedIndexedAccess</p>
<div class="cnblogs_code">
<pre>const obj: { : string } =<span style="color: rgba(0, 0, 0, 1)"> {};
const value </span>= obj.whatEverProperty; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string</span>
<span style="color: rgba(0, 0, 0, 1)">
const arr: string[] </span>=<span style="color: rgba(0, 0, 0, 1)"> [];
const value2 </span>= arr; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string</span></pre>
</div>
<p>TS 认为类型是 string, 但 run time 会发现类型是 undefined. </p>
<p>如果你觉得这样不安全, 那么可以开启 noUncheckedIndexedAccess: true</p>
<p>开启后, TS 类型变成 string | undefined. 这样就必须做类型判断确保不是 undefined 才使用. run time 就安全了. </p>
<div class="cnblogs_code">
<pre>const value = obj.whatEverProperty; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string | undefined</span>
const value2 = arr; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> string | undefind</span></pre>
</div>
<p>这个配置默认是没有开启的, 因为很多使用我们不需要这么严格的检查. 绝大部分情况, 它会很巧妙的不会是 undefined.</p>
<p> </p>
<h3>19. useDefineForClassFields</h3>
<p>请查看 TypeScript 复习与进阶三部曲 (1) – Type-only Field Declarations</p>
<p> </p>
<h3>20. noImplicitOverride</h3>
<p>请查看 TypeScript 复习与进阶三部曲 (1) – Override Property/Method</p>
<p> </p>
<h3>21. exactOptionalPropertyTypes</h3>
<p>请查看 TypeScript 复习与进阶三部曲 (1) – Optional Property</p>
<p> </p>
<h3>22. strict</h3>
<p>参考: "Strict Mode" TypeScript config options</p>
<p>它是一个 shortcut, 开启它的话代表一同开启几个严格模式.</p>
<p><img src="https://img2023.cnblogs.com/blog/641294/202211/641294-20221127211606309-1826169140.png"></p>
<p>这些是 TypeScript 选出来的. 以后可能还会增加. 想知道准确的可以到这里看 </p>
<p> </p>
<h3>23. esModuleInterop</h3>
<p>当 ES Module .mjs 要 import CommonJS .cjs 时就会有一些鬼跑出来。</p>
<p>通常可以用 esModuleInterop: true 来解决。详情可以看这篇: 知乎 – esModuleInterop 到底做了什么?</p>
<p> </p>
<h3>24. forceConsistentCasingInFileNames</h3>
<p>要求 import 的 file name 区分大小写。by default 是 false 不区分。想严格点区分当然是更好的。</p>
<p> </p>
<h3>25. isolatedModules</h3>
<p>用 Vite 时,isolatedModules 会配置为 true,当我们要 export 类型时,需要改写成 export type.</p>
<p><img src="https://img2023.cnblogs.com/blog/641294/202308/641294-20230816233908884-1169721467.png"></p>
<p>export type</p>
<p><img src="https://img2023.cnblogs.com/blog/641294/202308/641294-20230816233923753-922447154.png"></p>
<p>欲知详情可以参考这篇:tsconfig编译属性isolatedModules的作用</p>
<p> </p>
<h3>26. verbatimModuleSyntax</h3>
<p>用 svelte 时,它的 tsconfig 会继承自 svelte/tsconfig.json</p>
<p><img src="https://img2023.cnblogs.com/blog/641294/202311/641294-20231117171028883-1475453994.png"></p>
<p>里面就有设置 verbatimModuleSyntax</p>
<p><img src="https://img2023.cnblogs.com/blog/641294/202311/641294-20231117171209834-567715866.png"></p>
<p>true 以后,我们在 import 类型的使用需要特别声明 import type。</p>
<p> </p>
<h3>27. noPropertyAccessFromIndexSignature</h3>
<p><img src="https://img2024.cnblogs.com/blog/641294/202501/641294-20250123024725886-1536608266.png"></p>
<p>dataset 的类型是 Record<string, string | undefined>。</p>
<p>当设置 noPropertyAccessFromIndexSignature: true 时,如果我们用静态属性访问方式,它就会报错。</p>
<p>必须使用动态属性访问方式才行,像这样</p>
<p><img src="https://img2024.cnblogs.com/blog/641294/202501/641294-20250123025015514-52104687.png"></p>
<p> </p>
<h3>28. noUncheckedSideEffectImports</h3>
<p>v5.x 推出的,默认是 false,但 v6.0 以后默认变成 true 了。</p>
<p>它不允许在 .ts import .scss,像这样会报错</p>
<div class="cnblogs_code">
<pre>import '../Shared/layout.scss'; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Cannot find module or type declarations for side-effect import of '../Shared/layout.scss'.</span></pre>
</div>
<p>解决方法就是明确定义 .d.ts 允许它 import。</p>
<p>创建一个 global.d.ts 文件,然后里面 declare</p>
<div class="cnblogs_code">
<pre>declare module '*.scss';</pre>
</div>
<p>这样就行了。</p>
<p> </p><br><br>
来源:https://www.cnblogs.com/keatkeat/p/16204926.html
頁:
[1]