TypeScript 工程配置与构建
更新时间:2026-08-29。本文回答:tsconfig 怎么配才稳?
strict为什么必开?类型声明文件.d.ts是什么?TS 和 Vite/esbuild 怎么配合?
一、tsconfig.json:工程的类型宪法
tsconfig.json 统管类型检查与编译行为:
json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"noUncheckedIndexedAccess": true,
"outDir": "dist"
},
"include": ["src"]
}| 选项 | 作用 | 建议 |
|---|---|---|
strict | 开启全部严格检查(含 strictNullChecks) | 必开,否则类型形同虚设 |
target | 编译产出到哪版 JS | 跟随运行环境 |
moduleResolution | 模块解析策略 | 用打包器选 Bundler |
noUncheckedIndexedAccess | 数组/对象索引返回 T | undefined | 开启,强制处理越界 |
二、类型边界:编译期 vs 运行时
TS 的核心是类型擦除——编译后类型注解全部消失,运行时只剩纯 JS。这带来一个重要边界:
ts
function parse(input: unknown): number {
if (typeof input !== "number") {
throw new Error("expected number"); // 运行时仍需手动校验
}
return input;
}- 类型保证只在编译期有效;外部输入(API、JSON、DOM)必须在运行时校验(可用
zod等 Schema 库)。 - 这是 TS 与 Rust 所有权(编译期保内存安全)的根本区别:TS 不保运行时安全。
三、类型声明文件 .d.ts
.d.ts 是"只有类型、没有实现"的声明文件,用来给无类型的 JS 库补类型:
ts
// express.d.ts
declare module "legacy-lib" {
export function doThing(x: number): string;
}- 第三方库的类型来自
@types/*(DefinitelyTyped)或库自带。 - 自己写 JS 库想暴露类型,用
declaration: true让tsc自动生成.d.ts。
四、构建链路:tsc 与打包器分工
现代工程里,tsc 通常只做类型检查,真正的打包交给 Vite/esbuild/tsup(更快,且用 SWC/esbuild 做转译):
| 工具 | 角色 | 本站衔接 |
|---|---|---|
tsc | 类型检查(可 --noEmit) | 编译期质量闸门 |
| Vite | 开发服务器 + 构建 | 前端构建工具 |
| esbuild | 极速转译(Go 写) | 本站 VitePress 构建 同源技术栈 |
核心结论:类型检查与打包解耦——tsc 守质量,打包器拼速度。这点和本站强调的"分层职责"一致。
五、与工程化主线的衔接
| TS 工程要素 | 本站对应 | 衔接文档 |
|---|---|---|
| 严格类型闸门 | 异常安全/工程纪律 | 把错误前移 |
| 构建链路 | 前端构建工具演进 | Vite/esbuild 技术栈 |
| 类型即文档 | 设计原则 | 接口契约 |
| 包管理/模块 | 后端工程组织 | 工程分层 |
六、常见坑
- 不开
strict:项目初期图省事关掉,后期类型错误遍地,重构艰难——一开始就开。 - 混淆
tsc与打包器职责:用tsc既查类型又打包会很慢,现代工程让打包器干转译。 - 依赖无类型:引入无
.d.ts的库会得到any,用declare module补或换有类型的库。
一句话总结
TS 工程化 = tsconfig(strict 必开)定类型宪法 + .d.ts 补声明边界 + tsc 查类型、打包器(Vite/esbuild)做转译,把"类型正确"和"构建速度"各司其职。
回到总纲:TypeScript 从 JS 到 TS。