likes
comments
collection
share

你真的了解 tsconfig.json 吗?

作者站长头像
站长
· 阅读数 10

开始

平时我们开发都是直接脚手架生成了完整的项目模板,使用 TypeScript 的时候,tsconfig.json 文件也是给你配置好了,但是遇到 TS 报错的时候,又无从下手,所以把 TS 的配置梳理了一遍。

翻了很多网上的资料,发现配置项特别多,平时开发用到的时候,查找起来也非常困难,于是根据官方对 tsConfig 的配置分类,画了一个图,并且标出了重点需要了解的属性:

你真的了解 tsconfig.json 吗?

因为配置项比较多,有些配置看下来基本不会用到,所以这里也是详细了解了常用的一些配置,至于其他的配置,可以通过这张图以及下面的参考链接去学习。

现在来通过 vite 新建一个 react-ts 的项目,目录结构如下:

你真的了解 tsconfig.json 吗?

compilerOptions

compilerOptions 配置中按照配置的作用分为以下几类:

类型检查配置

这里重点需要关注的就是 strict 配置,只要开启了该配置,其中几个以 strict 开头的配置以及 no 开头的配置都会跟随开启。所以只需要配置一个 strict 就可以了,这样就可以对 any、this、空值等等类型进行检查,所以也是强烈推荐开启此配置项。

模块配置

模块配置也是整个 tsconfig 文件中重要的部分,需要了解的配置包括:

  • baseUrl:指定查找模块的基路径
  • paths:配置路径映射别名
  • module:指定项目的模块化规范
  • moduleResolution:指定模块的解析策略
  • resolveJsonModule:允许导入 json 文件
  • rootDir:指定输入目录,输出目录的结构会与其保持一致,默认值为输入文件的最长公共路径

baseUrl 定义了查找模块的基础路径,比如配置 baseUrl: '.',修改 main.tsx 文件就可以这么写:

import App from 'src/App.tsx'

// 相当于
import App from './src/App.tsx'

这么做编译不会报错,但是执行的时候是找不到路径的,所以需要搭配构建工具的别名配置才可以。

paths 配置也是一个意思,不过这是专门来设置别名的,同理也可以搭配 baseUrl 设置的基础路径来写:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
  }
}

同样这么做只是为了 TS 编译通过,执行的时候,还需配置构建工具。

module 配置则是指定项目的模块化规范,值可以是以下几种之一:

  • none
  • commonjs
  • amd
  • umd
  • system
  • es6/es2015
  • es2020
  • es2022
  • esnext
  • node16
  • nodenext

常用的场景可能是通过 babel 来进行打包,并不会用到 TS 的编译输出,不过改变 module 配置会影响 moduleResolution 的配置项。

moduleResolution 用来指定查找模块的解析策略,可选值有以下几个:

  • classic
  • node10/node
  • node16
  • nodenext
  • bundler

实际项目中用到的基本都是 node 值,这也表示对于查找模块的算法,NodeJS 提供的策略更为普遍。

resolveJsonModule 配置了才可以导入 json 文件,需要注意的是,moduleResolution 的值不能为 classic

rootDir 指定输入目录,并且如果 include 指定了 rootDir 之外的文件,则会报错,比如这么配置:

{
   "rootDir": "src",
   "include": ["./src", "vite.config.ts"]
}

此时则会报错:

你真的了解 tsconfig.json 吗?

告诉我们 vite.config.ts 不在我们的 rootDir 的输入目录中。

rootDir 的默认值也很有意思,默认为所有非声明输入文件的的最长公共路径,并且如果设置了 composite,则该默认值就为 tsconfig 所在目录。

生成配置

其中几个比较重要的配置有declarationnoEmitoutDir

declaration 生成 .d.ts 的类型声明文件。一般情况下,项目构建不会用到 TS 来编译,但是类型声明文件则可以通过 TS 来生成。除了 declaration 配置项,也可以通过 declarationMap 生成源映射文件,用于跳转到定义,declarationDir 指定类型声明文件的目录。

noEmit 则是不要生成 JS 源文件,类型声明文件,而是交给其他工具来进行编译,如果你的项目由 babel 等工具编辑,则可以启用该配置

outDir 配置用来指定生成文件的目录。

JS 支持配置

JS 配置则用于增量从 JS 迁移至 TS 的配置。一般在 TS 项目中导入 JS 文件,会报这么一个错误:

你真的了解 tsconfig.json 吗?

这时候可以添加 allowJs 的配置:

{
    "allowJs": true
}

则可以消除 JS 文件类型错误。

编辑器支持配置

该类配置项主要作用于 vscode 这种 IDE,项目中并不会用到,所以了解即可。

互操作约束配置

所谓互操作约束,其实就是关于文件导入导出的配置项。有以下几个配置需要关注:

  • allowSyntheticDefaultImports:: 启用可以在 TS 文件中使用默认导入,即使模块不存在默认导入也不会报错
  • esModuleInterop: 开启 TS 会对命名空间导入和默认导入做处理
  • isolatedModules: 启用会打开模块隔离

allowSyntheticDefaultImports 开启以后,像这种写法:

// 导入命名空间
import * as React from 'react'
import * as ReactDOM from 'react-dom/client'

// 开启 allowSyntheticDefaultImports: true
import React from 'react'
import ReactDOM from 'react-dom/client'

所以项目中一般都是这么写的,但也不需要开启该配置,因为 esModuleInterop 开启以后,该项也默认开启。

esModuleInterop 选项可以理解为对非 ES 模块导出的时候会做特殊处理,让其表现同 ES 模块一样,以下是官方提供的开启和关闭 esModuleInterop 编译结果不同的例子

你真的了解 tsconfig.json 吗?

关闭 esModuleInterop

你真的了解 tsconfig.json 吗?

开启 esModuleInterop

一般项目中如果引入了第三方的非 ES 模块的话,则需要开启该配置。

isolatedModules 配置打开模块隔离,用于类型导出时,其他的编译器为单个文件编译,无法联系上下文编译,会导致类型声明导出被删除,打开该配置,则会提示这种错误。

向后兼容性配置

该类配置主要是为了兼容早先的版本,推荐大家使用最新的 TS 版本即可。

语言和环境配置

重要的几个配置有jsxlibtarget

jsx 用来控制 jsx 如何生成 JS 文件的,主要作用于 tsx 文件,一般使用 React 来开发的时候,需要配置该项,不配置的话,使用 jsx 的时候会提示错误。

lib 则是用来配置内置的类型声明,比如内置类型 Map、Set 都需要配置该项,如果在浏览器中使用还需要配置 DOM、DOM.Iterator等配置,不配置的话,使用这些全局 API,TS 会提示报错。

target 配置则是指定 TS 编译成 JS 的语言版本,默认编译成 ES3,也可以选择高版本的 JS,比如 ES6、7、8等,一般我们使用其他打包工具,这个选项配置最新版本的 JS 即可。

编辑器诊断配置

该类配置用于 TS 编译的调试,一般来说,前端只会把 TS 作为类型约束工具,并不会用 TS 进行编译,所以也是了解即可。

项目配置

项目配置中的 composite 属性是一个比较重要的属性,它和下面提到的 references 配置相关。

composite 启用以后会强制执行某些限制:如果 rootDir 未设置,则指定 tsconfig.json 文件所在的目录为 rootDir,所有的实现的文件都需要被包括在 includes 或 files 选项中,否则会提示你哪些文件没有列出。开启以后,则 declaration 选项默认为 true。

files

files 配置用来列出需要编译的文件列表,一般用于文件较少的情况,如果需要使用 glob 匹配的话,则可以考虑使用 include 选项。

extends

extends 选项指定要继承的配置文件的路径,首先会加载当前配置,然后从继承配置中覆盖当前配置,注意 references 属性不会被继承

include

include 包含要进行编译的文件或者模式,模式可以使用通配符来进行匹配,支持以下几种匹配:

    • 通配符,匹配零个或多个字符
  • ? 通配符,匹配任何一个字符(这和正则表达式不一样,正则表达式中的 ? 匹配零个或一个字符)
  • **/ 通配符,匹配任意嵌套的目录

注意,如果已经设置了 files 属性的话,则 include 为 [] 数组。

exclude

exclude 配置用于指定跳过编译的文件列表或模式,同 include 配置原理,需要注意的是,exclude 配置用于排除 include 中指定的某部分文件,只是用来改变 include 中的文件。

references

references 配置是 TS3.0 以后引入的新功能,用于将一个大的 TS 项目变成更小的规模,这样做可以大大缩短构建时间,在组件之间强制实施逻辑分离,并以新的更好的方式组织代码。

简言之,就是 TS 项目可以引用另外一个 TS 项目,通过 path 指定引用项目的路径,或者是 tsconfig.json 的配置文件,就可以引用另外一个项目。

{
    "references": [
        { path: "../common", prepend: true }
    ]
}

引用有什么作用呢,其实就是执行 tsc --build 命令的时候,TS 会查找引用的项目,按照指定的顺序进行构建(可以配置 prepend 属性),这样一个大的项目就分散到一个个的小项目中,并且对于编辑器的压力也小了很多,编辑器内置 TS 会占用比较大的内存。

推荐配置

说了这么多配置,那么有没有推荐的配置可以参考呢?结合一些常用配置和笔者平时的工作经验,以及一些脚手架的模板,可以得到下面这样一个推荐配置供大家参考:

{
  "compilerOptions": {
    "target": "ES2015",
    "lib": ["dom", "dom.iterable", "esnext"], // 指定包含的内置类型,一般包含这三个就够了
    "module": "ESNext", // 推荐 ESM 规范,而不是 commonjs 规范
    "strict": true, // 强烈推荐开启,能防止很多错误,替代一部分的 eslint 功能
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true, // 强制大小写来区分文件名
    "resolveJsonModule": true, // 导入 json 文件必备配置
    "noFallthroughCasesInSwitch": true, // 确保 switch 语句中有 break、return、throw,否则会报错
  }
}

这里只是一个通用的推荐配置,针对不同的框架,比如 React、Vue,也会有不一样的配置,具体可以通过下面的官方推荐配置链接查找对于框架的配置。

后话

这些配置就说到这里,有些配置比较少见,所以也是依着官网的解释,表述了一遍,如果有错误的地方,欢迎指出。

平时开发中,就着各种模板就开始了,没有在意过这些细小而杂乱的配置,所以也是希望通过此篇,能让你对 TS 和 tsconfig.json 了解的更深,所以现在你了解 tsconfig.json 了吗?

参考

[1]Intro to the TSConfig Reference

[2]centralized-recommendations-for-tsconfig-bases

[3]了不起的 tsconfig.json 指南