嘿,朋友。如果你刚打开这个页面,大概是因为你的 TypeScript 项目要么跑不起来,要么代码风格乱成一团麻,要么队友跟你吵架说“这代码根本没法看”。
别慌,我懂那种感觉。我也踩过无数个坑——从 tsconfig.json 里的 strict: false 到 ESLint 报一堆看不懂的警告,再到 Prettier 和 ESLint 互相打架。今天咱们不聊枯燥的官方文档,就聊聊怎么把一个“能跑”的项目,变成一个“能维护、能协作、能睡觉”的健康项目。
第一步:tsconfig.json——项目的灵魂,但别让它太“宽容”
tsconfig.json 是 TypeScript 项目的配置中心。很多人第一步就犯错了:直接用 tsc --init 生成默认配置,然后改都不改就开工。
默认配置是什么?strict 是 false。这意味着什么?意味着你可以写 any 类型而不被警告,可以访问未定义的属性,可以比较不相容的类型……项目越大,bug 越多。
最小化但严格的推荐配置
{
"compilerOptions": {
/* 基础设置 */
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
/* 严格类型检查 - 这是关键!*/
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitAny": true,
"strictNullChecks": true,
/* 其他实用设置 */
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
/* 路径别名 - 让导入更清晰 */
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
常见坑点解析
坑1:strict: false 是万恶之源
很多教程为了“简单”,建议关闭严格模式。但对于一个想要长期维护的项目,strict: true 是你最好的朋友。它强迫你处理 null、undefined,禁止隐式 any。刚开始会觉得麻烦,但三个月后你会感谢它。
坑2:noUncheckedIndexedAccess 的陷阱
这是 TypeScript 5.0+ 的新特性。当你访问数组或对象时,如果类型是 string | undefined,你必须处理 undefined 的情况。
// 假设 users 是一个对象,key 是字符串
const users: Record<string, User> = { ... };
// 这会在 strict + noUncheckedIndexedAccess 下报错
const user = users['non-existent-key']; // 类型是 User | undefined
// 正确做法
const user = users['non-existent-key'] ?? getDefaultUser();
if (user) {
// 只有这里 TypeScript 才确定 user 不是 undefined
console.log(user.name);
}
坑3:路径别名与 IDE 不同步
你在 tsconfig.json 里配置了 @/components/Button,但 VS Code 还是红线报错。别急,这不是配置错了,而是:
- 确保你安装了
TypeScript扩展 - 重启 VS Code
- 如果还不行,检查
.vscode/settings.json里是否有覆盖配置
第二步:ESLint——不只是检查,更是规范
ESLint 是 JavaScript/TypeScript 的 lint 工具。它能抓出语法错误、潜在 bug,甚至强制代码风格。
现代 ESLint 配置(Flat Config)
注意:ESLint 9 引入了新的“Flat Config”格式,旧版的 eslint.config.js 写法正在被淘汰。
// eslint.config.js (ESLint 9+)
import tseslint from 'typescript-eslint';
import prettier from 'eslint-plugin-prettier/recommended';
export default tseslint.config(
...tseslint.configs.recommended,
{
languageOptions: {
parserOptions: {
project: './tsconfig.json', // 让类型感知规则生效
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
// 常见规则调整
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'@typescript-eslint/prefer-optional-chain': 'error',
'no-console': ['warn', { allow: ['warn', 'error'] }],
},
},
// 忽略文件
{
ignores: ['dist/**', 'node_modules/**', '*.config.js'],
},
// 集成 Prettier
prettier,
);
关键规则解释
@typescript-eslint/no-explicit-any
禁止使用 any。如果必须用,用 unknown 代替,然后进行类型守卫。
// 错误
function handleData(data: any) {
return data.value;
}
// 正确
function handleData(data: unknown) {
if (typeof data === 'object' && data !== null && 'value' in data) {
return (data as { value: string }).value;
}
throw new TypeError('Invalid data');
}
@typescript-eslint/no-unused-vars
禁止未使用的变量。但有时候前缀下划线 _ 表示“我故意不用”,这个规则可以配置为忽略这类变量。
no-console
生产环境通常不需要 console.log。设为 warn 级别,让你在开发时能看日志,但 CI 中会提醒你清理。
ESLint + TypeScript 的协同陷阱
最大的坑:类型感知规则需要指向 tsconfig.json。
如果在 ESLint 配置中忘记设置 parserOptions.project,很多高级规则(如 @typescript-eslint/no-unsafe-member-access)就不会生效,因为它们需要知道类型信息才能判断。
第三步:Prettier——让代码自动格式化,释放双手
Prettier 是一个“ Opinionated ”的代码格式化工具。它不管你的逻辑对不对,只关心代码长得漂不漂亮。
配置示例
// .prettierrc
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"printWidth": 100,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always"
}
ESLint 与 Prettier 打架?不存在的
以前这两个工具经常冲突。ESLint 可能要求分号,Prettier 要求不用;ESLint 要求双引号,Prettier 要求单引号。
解决方法:使用 eslint-config-prettier 或 eslint-plugin-prettier。
它们的作用是告诉 ESLint:“遇到格式相关的规则,全部关闭,交给 Prettier 处理。” 这样你就只需要维护一套规则。
在上面的 eslint.config.js 示例中,prettier 被添加到配置末尾,这就是关键。
第四步:集成到工作流——VS Code 配置
光有配置文件不够,你需要让编辑器自动帮你格式化、自动检查。
.vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"typescript.preferences.importModuleSpecifier": "shortest",
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
}
}
关键点:
editor.formatOnSave: 保存时自动格式化editor.codeActionsOnSave: 保存时自动运行 ESLint fixsource.organizeImports: 自动整理 import 语句(移除未使用的、按规则排序)
推荐安装的 VS Code 扩展
- ESLint - 实时报错,提供快速修复
- Prettier - Code formatter - 格式化引擎
- TypeScript and JavaScript Language Features - 内置,别删
- Import Cost - 显示每个 import 的大小,帮助你优化打包
第五步:常见实战问题与解决方案
问题1:类型定义文件报错
有时候第三方库没有类型定义,或者类型定义有冲突。
解决方案:
- 不要删除
@types/*包,而是创建src/types/目录,写自己的声明文件 - 使用
declare module 'some-library';来桥接
问题2:测试文件配置不同
测试文件(如 Jest/Vitest)通常不需要严格的生产级配置。
解决方案:
- 为测试创建单独的
tsconfig.test.json,可以放宽一些规则 - 在 ESLint 中为测试文件配置不同的规则集
// eslint.config.js 中添加测试文件配置
tseslint.config({
files: ['**/*.test.ts', '**/*.spec.ts'],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'no-console': 'off',
},
}),
问题3:Vue/React 框架特殊配置
如果你用 Vue 3 + TypeScript,需要额外的插件。
npm i -D eslint-plugin-vue
// eslint.config.js
import vue from 'eslint-plugin-vue';
import vueTs from 'vue-eslint-parser';
export default tseslint.config(
...tseslint.configs.recommended,
{
files: ['**/*.vue'],
languageOptions: {
parser: vueTs,
},
plugins: {
vue,
},
rules: {
'vue/multi-word-component-names': 'off',
},
},
prettier,
);
问题4:Monorepo 项目
如果是 Monorepo(如 Turborepo、Nx),每个包可能有自己的 tsconfig.json。
解决方案:
- 使用
extends共享基础配置 - 在每个包的 ESLint 配置中指向对应的
tsconfig.json
// packages/shared/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist"
}
}
第六步:CI/CD 集成——把好最后一道关
本地配置再好,也挡不住队友强制提交。你需要在 CI 流程中加上检查。
GitHub Actions 示例
# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install
run: npm ci
- name: Type Check
run: npm run type-check
- name: ESLint
run: npm run lint
- name: Prettier Check
run: npx prettier --check "src/**/*.{ts,tsx,js,jsx,vue}"
脚本定义
在 package.json 中:
{
"scripts": {
"type-check": "tsc --noEmit",
"lint": "eslint . --fix",
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,vue}\"",
"prepare": "husky install"
}
}
加入 Husky——提交前自动检查
Husky 是 Git hooks 管理工具。配置后,每次 git commit 或 git push 前自动运行检查。
npx husky add .husky/pre-commit "npm run lint && npm run type-check"
这样,不符合规范的代码根本提交不上去。
第七步:最佳实践总结(给小朋友也能听懂的版本)
想象你在建一座房子:
- tsconfig.json 是地基。地基要牢固(
strict: true),不然房子建得越高越容易塌。 - ESLint 是质检员。它检查你有没有用错材料(
any类型)、有没有结构问题(潜在 bug)。 - Prettier 是装修队。它不管房子结不结实,只管漆刷得漂不漂亮、家具摆得整不整齐。
- VS Code 配置 是自动化机器人。你不用自己动手,保存文件时机器人自动帮你质检+装修。
- CI/CD 是最后的验收环节。房子盖好后,还得请监理再来检查一遍,确保没有漏网之鱼。
最后的小贴士
- 不要追求完美配置:先跑起来,再逐步收紧规则。一次性开启所有严格规则可能会让你现有代码报错几百个,慢慢修会很痛苦。
- 团队统一配置:把配置提交到代码库,每个人拉的代码都有同样的检查标准。
- 定期升级:TypeScript、ESLint、Prettier 都在快速迭代,定期
npm update并阅读 changelog,新特性往往能帮你发现更多问题。
好了,现在去打开你的 tsconfig.json 吧,把 strict 改成 true。从今天开始,你的代码会更干净,头发也会掉得少一点。
