TypeScript 性能优化
TypeScript 代码最终会编译成 JavaScript,运行时性能主要取决于产物质量与写法;而"编译速度"则直接受 tsconfig 与工程结构影响。本节从编译提速、产物瘦身、运行时细节三方面给出可落地的建议。
用增量构建与跳过类型库提速
开启 incremental 与 skipLibCheck 是最快的两招:前者复用 .tsbuildinfo,后者不再逐个检查 node_modules 里庞大的 .d.ts 声明文件:
{
"compilerOptions": {
"incremental": true,
"skipLibCheck": true
}
}
配合项目引用(tsc -b)拆分大型工程,还能进一步缩小每次类型检查的范围,把"全量编译"变成"按需增量"。
让产物更小、更利于 tree-shaking
- 尽量使用具名导入,并让第三方库提供 ESM 产物;
- 避免在模块顶层写有副作用的代码(如直接调用 console、修改全局变量),否则打包器无法摇树;
- 类型导入尽量写成
import type,让类型在编译后彻底消失:
// 假设 ./types 中导出 interface User
import type { User } from "./types"; // 只做类型,产物中无此导入
import { toUpper } from "./utils"; // 真正的运行时导入
const u: User = { name: "ts" };
console.log(toUpper(u.name)); // 输出:TS
慎用 enum 等带运行时开销的语法
TS 的 enum 会生成一段运行时对象代码。若追求零成本,可改用 const 对象 + as const,既保留类型提示又不产生额外产物:
const Status = {
Active: "active",
Done: "done",
} as const;
type Status = (typeof Status)[keyof typeof Status];
function run(s: Status): string {
return s === Status.Active ? "进行中" : "已完成";
}
console.log(run(Status.Done)); // 输出:已完成
装饰器、reflect-metadata 等特性同样会引入额外运行时依赖,按需使用,不要为了"高级"而滥用。
运行时性能要点
- 热循环里避免创建闭包与临时对象;能用 for 循环就不必用 forEach/map 反复摊派函数调用。
- 大集合善用 Set/Map,避免在数组上频繁 indexOf;能用只读结构就少做深拷贝。
- 类型体操(infer、条件类型递归)只发生在编译期,不影响运行;但要警惕深度递归泛型把编译器拖慢。
小结
性能优化分两层:工程层用 incremental、skipLibCheck 与项目引用把编译速度提上去;运行层用 import type、const 断言、克制 enum 让产物更小。原则是"先测量、再优化",避免无依据的微优化。