想获取更多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
里指定的main
或module
字段 - 自动处理
/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 服务器上就挂掉
最后说两句
配置这东西没有标准答案,我们团队现在的策略是:
- te-react-app 或 vite 这些工具生成基础配置
- 们自己的 strict 规范
- 目特点调整 paths 之类的配置
- 明显的部分(比如 node 项目和浏览器项目)抽成 preset,新项目直接继承
TypeScript 的配置就像装修房子,刚开始总觉得越多越好,后来才发现简洁实用最重要。毕竟,我们的目标是写业务代码,不是玩配置杂技,对吧?
关注我,了解更多前端面试相关的知识。
需要前端刷题的同学可以用这个宝藏工具 :fe.ecool.fun
转载请注明出处。