TypeScript – tsconfig

前言

上一篇 TypeScript – Get Started 使用了命令

tsc index.ts --module es2015

很少人会在命令时给写 config, 更正规的做法是创建一个 tsconfig.json 把所有 config 写到里面去. 类似 webpack.config.js, tailwind.config.js, .eslintrc.json, prettier.config.js, stylelint.config.js

 

参考

详解tsconfig.json文件 (must read)

 

Create tsconfig.json

tsc --init

运行命令后就会创建出 tsconfig.json 了

里面包含了所有 config 和 注释. 有需要的就开启.

 

常用 Config

1. target

{
    "target": "es2016"
}

target 指的是 TypeScript transpile 出来想要生成什么 version 的 ECMAScript

ES3 已经完全没有人用了, ES5 应该是目前最低的配置了.

tsconfig 的 默认是生成 ES2016 也就是 ES7. 毕竟很少人要支持 Internet Explorer 了.

Angular 默认是生成 ES2017.

 

2. lib

{
    "target": "ES2016",
    "lib": ["DOM", "ES2016", "ES2017.Object"],
}

lib 和 target 通常是一套的. 它指的是在开发阶段, TypeScript 对应的 ECMAScript version.

我举个具体的例子你就明白了. 假设项目需要支持比较旧的游览器, 那个游览器只支持 ES2016, 那么 target 就 set 成 ES2016 咯.

但是呢, 开发人员又很想用 ES2017 的某个功能, 比如 Object.values. 那怎么办? 要让游览器支持 Object.values 可以通过 polyfill (比如引入 core.js)

但是在开发阶段, TypeScript 不知道你有 polyfill, 所以如果你写 Object.values 它就报错提示你 (因为你 target ES2016 不能超过这个功能范围). 所以 lib 就排上用场了.

lib 就是让你声明开发阶段, 你的 ECMAScript version. 

"DOM" 声明, 这个 TypeScript 用于游览器, 所以可以调用 document, window 这类接口

"ES2016" 声明, TypeScript 能写到 ES2016 的语法和各种 build-in 方法

"ES2017.Object" 声明, TypeScript 还能写到 ES2017 Object 的 build-in 方法 (比如 Object.values).

所以 target, lib, polyfill 的玩法就是这样啦.

注: lib 如果没有声明它, 那么它会依据不同的 target 设定 default 的 lib, 一旦声明了它就是完全 override 掉 default 的.

How to enable Internet Explorer on Windows 11

我为了做测试特地学了如何在 Windows 11 开启 Internel Explorer, 这里做个记入呗, 参考: Youtube – How to enable Internet Explorer on Windows 11

打开 edge 游览器 > 右上角 ... 打开选择 setting > 左边选 default browser > 然后 allow sites > add 要测试的页面.

接着打开测试页面就可以了.

更新: 2 Jun 2022

目前 standard 的 target 是 es2017, 经常遇到 Array.flatMap 无法使用的烦恼. 那么可以这样配置

"target": "es2017",
"lib": [
  "DOM", "DOM.Iterable", "ES2017", "ES2019.Array"
],

注: DOM.Iterable 是必须的哦, 不然就会出现如下错误

 

3. files, include, exclude

这 3 属性都是用来设定 .ts files 扫描范围的

默认情况下, tsconfig sibling 和 descendant 的 .ts 都会被 transpile to .js

例子说明:

注: 它不是 complilerOptions 的属性哦, 是最外面对象的属性

这是 files 结构

files 只能指定具体的 file 不能写 glob

include 和 exclude 则可以写 glob

通常设置的方式是这样的, include 你要的大范围, files 一些例外 (out of inclde 范围的), exclude 一些例外 (在 include 范围内的)

 

4. outDir & rootDir

{
    "rootDir": "./src",
    "outDir": "./dist",
}

rootDir 我也不清楚什么时候会用到, outDir 就是指 transpile 后的 .js 要 output 到哪里. 默认情况下是 output 到 .ts 的 sibling.

配置成 ./dist 以后, 它就会创建一个 dist folder, 然后依据 .ts 结构 output 到 dist 里面.

 

5. removeComments

{
    "removeComments": true,    
}

顾名思义, 就是把 .ts 里面的 comment 在 transpile 过程中移除. .js file 里面就看不到任何 comment 了

 

6. sourceMap, inlineSourceMap

{
    "sourceMap": true,
}

transpile 的 JavaScript 阅读非常不友好, runtime debug 就会很困难. 开启 sourceMap compiler 就会创建一个 .map 的 file

这样 chrome dev tool / debuger 就可以找到 erorr 在 .ts 源文件的位置. 开发阶段必开.

p.s: inlineSourceMap 就是它会把 mapping 放入 .js 文件, 而不是创建都都一个 .map 的 file.

 

7. module

JavaScript 的 modular 是出了名的混乱. 可以看这篇 JavaScript – Modular.

JavaScript 又可以用于前端 Browser 和后端 Node.js. 所以 TypeScript 需要兼顾到这些.

如果是 for Node.js 那么 module 的值是 "CommonJS" 或者 "ES2020".

如果是 for Browser 而且有使用 module bundler (e.g. Webpack), 那么 module 设置成 "ES2020" 就可以了, bunlder 会处理好一切. (像 Angular 那样)

如果没有使用 module bundler, 设置 "ES2020" 就表示完全使用游览器的 ES Module. 通常不是一个好主意. 现阶段最好还是使用 SystemJS 或者 RequireJS 来管理前端模块 (不然会需要加载很多 js files)

一个折中的方案是用 TypeScript Compiler 的 bundler 配上 SystemJS 或 RequireJS. module 设置成 "AMD" 或者 "System". 这篇

example:

 

 

8. moduleResolution

它有 2 个值, "Classic""Node". 默认是 Classic, 但凡你有用 node_modules 就设置成 Node 就对了.

它指的是当我们写 import {} from 'xxx' 的时候, TypeScript Compiler 怎么去找到这个 module.

想具体了解的话建议看这篇: 深入理解TypeScript的模块系统, 讲的比较清楚.

我自己的测试是, 如果 "module": "ES2020", 那么不设置 "moduleResolution": "node" 会报错

如果 "module": "CommonJS" 就不会报错. 这个是 esbuild 的测试场景.

v5.0 后多了一个值 "Bundler",bundler 是 for Vite、Webpack 这些的。

用了 Bundler 以后 allowSyntheticDefaultImports: true 就不需要了,这个本来是 for import DefaultModule from 'module' 用的。

 

9. outFile

上面有提到 TypeScript bundler, 它只是一个简单 for 单元测试的工具, TypeScript 的职责是 transpile 不是 bundle. 

bundle 还是用 Webpack 之类的比较好.

{
    "module": "System",
    "outFile": "./dist/bundle.js",  
}

设置 outFile 以后, 最后只会生成一个 bundle.js 所有代码都在里头. 必须配上 SystemJS 或者 RequireJS 才能发挥功效哦.

 

10. declaration, declarationDir

{
    "declaration": true
}

TypeScript transpile 除了生成 .js 还可以生成 .d.ts 类型文件.

这个对 Library 发布就很重要, 因为有了 .d.ts, 那些使用 Library 开发者即使没有用 TypeScript 也可以通过 VS Code 得到很多类型的提示.

 

11. allowJs, checkJs

{
    "allowJs": true,
    "checkJs": true,
}

TypeScript 默认配置是不允许 import js 的, 如果想 import js 文件那么需要在 tsconfig 设置 allowJs

JavaScript 是没有类型检查的, 但如果你想让它带有一点类型检查, 但又不要像 TypeScript 那么 "类型", 可以开启 checkJs

这个功能和 VS Code 的 Working with JavaScript 是一样的

// @ts-check, // @ts-ignore // @ts-nocheck 配上 checkJs 一同使用

使用注释来声明类型

p.s. 不推荐使用 allowJs, 比较好的做法是提供 .d.ts 文件

 

12. typeRoots, types

当使用没有类型的 JavaScript Library 时, 需要提供 .d.ts Type Declarations.

大部分第三方 Library 的 .d.ts 都可以到 npm 下载, 下载后会被收入到 node_modules/@types 里面.

但如果没有在 npm 找到. 那就需要我们自己编写 .d.ts.

then 这个文件不可能放到 node_modules 嘛, 所以得在外面开一个 types folders

我们需要让 TypeScript compiler 知道这个 folder, 所以需要在 tsconfig.json 添加上 typeRoots

{
  "compilerOptions": {
    "typeRoots": ["./node_modules/@types", "./types"],
    "types": ["jquery", "my-library"]
  }
}

override typesRoots 必须把 node_modules/@types 补回去哦

types 做用是进一步 filter, 在 typeRoots folder 里, 只有 jquery 和 my-library 被纳入, 其它无视.

注: 虽然上面理论是这样说, 但在开发的时候, 我发现不管我 .d.ts 放哪里都是可以找到类型的..懒得去研究, 等以后看看有没有问题呗

 

13. paths

{
    "paths": {
      "local-library": ["./local-library/local-library"],
      "local-library/*": ["./local-library/*"],
    },
}

这个常用在本地 Library. 

当配置好 paths 以后, import 的时候就不走 relative path 了, 反而是像 import node_modules 的 module 那样, 直接写名字

import { localLibraryFunction } from 'local-library';
import { abc } from 'local-library/abc';

这些名字就会去 tsconfig paths 做匹配, 然后去寻找 .ts 文件. 它就是这样串起来用的. 

 

14. experimentalDecorators

参考: angular2 学习笔记 (Typescript - Attribute & reflection & decorator)

想做到类似 C# 那种 Data Annotation Validation, 反射, 就需要借助 TypeScript 的 Decorators 功能.

 

15. downlevelIteration

参考: Downlevel Iteration - downlevelIteration 

这个是针对 target: es5, 使用 for of 的时候它会编辑成什么格式. Angular 的 tsconfig 有开启, 所以我这里提一下. 

 

17. importHelpers

参考: Import Helpers - importHelpers

有些代码被 compile 之后会很长, 比如 downlevelIteration, extending class, spreading arrays or objects, and async operations

开启 importHelpers, 它会 import from 'tslib' 把它们封装起来. 可以节省代码量. 随着 target 越来越高, downlevelIteration 和 importHelpers 以后应该是不需要的了.

目前 Angular tsconfig 也是有开启的. 另外如果你想提供自己的 'tslib' 可以开启 noEmitHelpers.

 

18. noUncheckedIndexedAccess

参考: Youtube – TypeScript option you want to enable beyond strict : noUncheckedIndexedAccess

const obj: { [prop: string]: string } = {};
const value = obj.whatEverProperty; // string

const arr: string[] = [];
const value2 = arr[0]; // string

TS 认为类型是 string, 但 run time 会发现类型是 undefined. 

如果你觉得这样不安全, 那么可以开启 noUncheckedIndexedAccess: true

开启后, TS 类型变成 string | undefined. 这样就必须做类型判断确保不是 undefined 才使用. run time 就安全了. 

const value = obj.whatEverProperty; // string | undefined
const value2 = arr[0]; // string | undefind

这个配置默认是没有开启的, 因为很多使用我们不需要这么严格的检查. 绝大部分情况, 它会很巧妙的不会是 undefined.

 

19. useDefineForClassFields

请查看 TypeScript 复习与进阶三部曲 (1) – Type-only Field Declarations

 

20. noImplicitOverride

请查看 TypeScript 复习与进阶三部曲 (1) – Override Property/Method

 

21. exactOptionalPropertyTypes

请查看 TypeScript 复习与进阶三部曲 (1) – Optional Property

 

22. strict

参考: "Strict Mode" TypeScript config options

它是一个 shortcut, 开启它的话代表一同开启几个严格模式.

这些是 TypeScript 选出来的. 以后可能还会增加. 想知道准确的可以到这里看 

 

23. esModuleInterop

ES Module .mjs 要 import CommonJS .cjs 时就会有一些鬼跑出来。

通常可以用 esModuleInterop: true 来解决。详情可以看这篇: 知乎 – esModuleInterop 到底做了什么?

 

24. forceConsistentCasingInFileNames

要求 import 的 file name 区分大小写。by default 是 false 不区分。想严格点区分当然是更好的。

 

25. isolatedModules

Vite 时,isolatedModules 会配置为 true,当我们要 export 类型时,需要改写成 export type.

export type

欲知详情可以参考这篇:tsconfig编译属性isolatedModules的作用

 

26. verbatimModuleSyntax

svelte 时,它的 tsconfig 会继承自 svelte/tsconfig.json

里面就有设置 verbatimModuleSyntax

true 以后,我们在 import 类型的使用需要特别声明 import type

 

posted @ 2022-04-28 22:47  兴杰  阅读(1290)  评论(0编辑  收藏  举报