TSConfig 这玩意,配好了真能少加两天班

想获取更多2025年最新前端场景题可以看这里fe.ecool.fun

大家好,我是刘布斯。

前几天帮团队里新来的小伙 review 代码,发现他提交的 PR 里有个 TypeScript 类型问题折腾了半天。

我随口问了句:"你 tsconfig 里配了 strict 模式没?" 结果这哥们一脸茫然地看着我------又是一个被 create-react-app 这类脚手架惯坏的孩子。

说起来,我刚接触 TypeScript 那会儿(那时候还是 1.6 版本),配置 tsconfig.json 简直就是玄学。现在十年过去了,这玩意儿虽然文档越来越完善,但选项也越来越多,今天就跟大家聊聊那些真正影响日常开发的配置项。

踩过的 strict 模式坑

早在 2017 年,我们团队决定全面转向 TypeScript 时,第一个争议就是要不要开 strict 模式。当时团队里有个 Angular 老司机坚持要开,而其他从 JavaScript 转过来的同事(包括我)都觉得这玩意儿太烦人------一个简单的对象字面量都要写类型断言,这不是自虐吗?

但是三个月后我们项目遇到个生产环境 bug,就是因为一个可能是 undefined 的值没做检查。那天晚上十点,我们一群人围着电脑查问题的时候,那位 Angular 老司机就站在后面幽幽地说:"要是开了 strictNullChecks..."

现在我的原则很简单:新项目无脑开 strict,老项目逐步开。这个复合选项包含的几个子项都特别实用:

json 复制代码
{
  "compilerOptions": {
    "strict": true,
    // 相当于同时开启:
    // "noImplicitAny": true,
    // "strictNullChecks": true,
    // "strictFunctionTypes": true,
    // "strictBindCallApply": true,
    // "strictPropertyInitialization": true,
    // "noImplicitThis": true,
    // "alwaysStrict": true
  }
}

特别是 strictNullChecks,它能帮你避免"undefined is not a function"这种经典错误。虽然刚开始写代码会多花 10% 的时间,但调试省下的时间绝对不止这个数。

moduleResolution 的玄学问题

去年我们有个项目要把部分代码共享给后端团队用,结果他们那边死活编译不过。折腾了一下午才发现,我们用的是 "node" 解析策略,他们那用的是 "classic"。这个配置项决定了 TypeScript 怎么查找模块:

json 复制代码
{
  "compilerOptions": {
    "moduleResolution": "node" // 或者是 "classic"
  }
}

简单点说,就是告诉TypeScript:"当你看到import 'lodash'这种语句时,该去哪儿找这个模块"。就像快递员送包裹,得知道是按门牌号逐户找(classic)还是直接查物业登记表(node)。

它有两个主要候选值:

1."node"(现代项目首选)

  • 模拟Node.js的require()解析逻辑
  • 会先找node_modules/lodash,再找package.json里指定的mainmodule字段
  • 自动处理/index.ts这类默认文件
  • 举个实战例子:当你import axios from 'axios'时,它会沿着目录向上递归查找node_modules,就像Node.js真正运行时那样

2."classic"(上古遗产)

  • peScript早期的解析方式
  • 只傻傻地按相对路径查找,不会自动识别node_modules
  • 需要手动写import axios from '../node_modules/axios'这种反人类的路径
  • 我上次见到有人用这个配置还是在维护一个2014年的AngularJS项目

还有两个算比较常用的值:

  • "node16"/"nodenext" :Node.js的ESM模块解析规则,处理.mjs/.cjs扩展名区分(TypeScript 4.7+)
  • "bundler" :专为现代打包工具设计的模式,要求配合"module": "esnext"使用(TypeScript 5.0+)

现在的项目基本上都用 "node",除非你在搞什么上古时代的遗产代码。但有意思的是,create-react-app 生成的 tsconfig 里从来不显式写这个配置,因为他们的 webpack 配置里已经处理好了------这也就是为什么很多前端同学不知道这回事。

baseUrl 和 paths:别再用../../../../了

我见过最夸张的相对路径是这样的:

js 复制代码
import { Button } from '../../../../../components/ui/Button'

这种写法的可读性太差了,其实可以用 baseUrl + paths 解决:

json 复制代码
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@components/*": ["components/*"],
      "@utils/*": ["utils/*"]
    }
  }
}

这样导入就清爽多了:

js 复制代码
import { Button } from '@components/ui/Button'

不过要注意,这只是一个 TypeScript 的编译时特性。如果你用的打包工具(比如 webpack)不认识这个配置,还得在对应的配置里再加一遍。比如我们的 Vue 项目需要在 vite.config.ts 里加了 alias 配置才行。

让人又爱又恨的 incremental 编译

TypeScript 3.4 引入了 incremental 编译,理论上能大幅提升编译速度。但实际用起来...emmm,看人品。

json 复制代码
{
  "compilerOptions": {
    "incremental": true
  }
}

这个选项会让 TypeScript 生成 .tsbuildinfo 文件来存储编译信息。理论上第二次编译会快很多,但我们那个 monorepo 项目里,有时候这个缓存文件会出问题,反而导致编译失败。我的经验是:中小型项目大胆开,大型 monorepo 项目...做好随时删 .tsbuildinfo 文件的准备。

那些容易被忽视但实用的配置

  • ModuleInterop :如果你曾经被 import * as React from 'react' 这种写法恶心到过,这个配置能让你回归正常的 import React from 'react'
  • skipLibCheck:跳过声明文件的类型检查,能显著提升编译速度,特别是当你用了很多第三方库时。虽然理论上可能漏掉一些类型错误,但五年了我还没遇到过因此产生的问题
  • forceConsistentCasingInFileNames:这个配置特别适合我们团队那个总在 Mac 和 Windows 之间切换的倒霉同事。开启后,文件名大小写不一致直接报错,避免你在 Mac 上开发好好的,部署到 Linux 服务器上就挂掉

最后说两句

配置这东西没有标准答案,我们团队现在的策略是:

  1. te-react-app 或 vite 这些工具生成基础配置
  2. 们自己的 strict 规范
  3. 目特点调整 paths 之类的配置
  4. 明显的部分(比如 node 项目和浏览器项目)抽成 preset,新项目直接继承

TypeScript 的配置就像装修房子,刚开始总觉得越多越好,后来才发现简洁实用最重要。毕竟,我们的目标是写业务代码,不是玩配置杂技,对吧?

关注我,了解更多前端面试相关的知识。

需要前端刷题的同学可以用这个宝藏工具fe.ecool.fun

转载请注明出处。

相关推荐
好好研究22 分钟前
使用JavaScript实现轮播图的自动切换和左右箭头切换效果
开发语言·前端·javascript·css·html
程序视点4 小时前
IObit Uninstaller Pro专业卸载,免激活版本,卸载清理注册表,彻底告别软件残留
前端·windows·后端
前端程序媛-Tian5 小时前
【dropdown组件填坑指南】—怎么实现下拉框的位置计算
前端·javascript·vue
嘉琪0015 小时前
实现视频实时马赛克
linux·前端·javascript
烛阴5 小时前
Smoothstep
前端·webgl
若梦plus6 小时前
Eslint中微内核&插件化思想的应用
前端·eslint
爱分享的程序员6 小时前
前端面试专栏-前沿技术:30.跨端开发技术(React Native、Flutter)
前端·javascript·面试
超级土豆粉6 小时前
Taro 位置相关 API 介绍
前端·javascript·react.js·taro
若梦plus6 小时前
Webpack中微内核&插件化思想的应用
前端·webpack
若梦plus6 小时前
微内核&插件化设计思想
前端