TypeScript 性能优化
TypeScript 项目的性能优化涉及编译速度、运行时性能和代码体积等多个方面。
本教程介绍常见的性能优化技巧,帮助构建更高效的 TypeScript 应用。
为什么需要性能优化
TypeScript 虽然提供了强大的类型系统,但使用不当会影响编译速度和运行性能。
大型项目的编译可能需要数分钟,严重影响开发体验。
本教程介绍的配置和技巧可以显著提升 TypeScript 项目的性能。
优化目标:更快的编译速度、更小的打包体积、更高的运行时性能。
编译配置优化
通过优化 tsconfig.json 配置来提升编译速度。
tsconfig.json 优化配置
"compilerOptions": {
// 启用增量编译,保存上次编译信息
"incremental": true,
// 跳过 node_modules 的类型检查
// 大幅提升编译速度
"skipLibCheck": true,
// 跳过声明文件的生成(仅在最终构建时生成)
"noEmit": true,
// 启用快速增量构建
"assumeChangesOnlyAffectDirectDependencies": true,
// 并行执行
"parallel": true,
// 启用缓存
"tsBuildInfoFile": ".tsbuildinfo",
// 不需要解析的文件
"exclude": [
"node_modules",
"dist",
"build",
"**/*.test.ts"
]
}
}
skipLibCheck:这是最重要的优化选项,可以将编译时间减少 50% 以上。
项目引用优化
使用项目引用将大型项目拆分为小模块,实现增量编译。
packages/utils/tsconfig.json
// 继承基础配置
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"outDir": "./dist",
"declaration": true,
"declarationMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
composite:启用后,TypeScript 会生成 .tsbuildinfo 文件来加速后续编译。
类型推断优化
充分利用 TypeScript 的类型推断,避免过度标注。
const name: string = "Alice";
const age: number = 25;
const isActive: boolean = true;
// 好的写法:利用类型推断
const name = "Alice";
const age = 25;
const isActive = true;
// 函数返回值类型可以省略(TypeScript 会自动推断)
function add(a: number, b: number) {
return a + b;
}
// 复杂对象使用类型推断
const user = {
id: 1,
name: "Bob",
email: "bob@example.com"
};
// TypeScript 会推断出:
// { id: number; name: string; email: string }
// 只有在类型推断不准确时才需要显式标注
const elements: HTMLElement[] = [];
减少标注:TypeScript 的类型推断已经很智能,大部分情况下不需要显式标注类型。
避免使用 any
使用 any 会失去类型检查的优势,影响运行时性能。
实例
function processData(data: any): any {
return data.value;
}
// 好的写法:使用 unknown 或具体类型
function processData<T extends { value: string }>(data: T): string {
return data.value;
}
// 如果真的不知道类型,使用 unknown
function parseJSON(json: string): unknown {
return JSON.parse(json);
}
// 使用时进行类型检查
const data = parseJSON('{"key": "value"}');
if (typeof data === "object" && data !== null) {
const obj = data as { key: string };
console.log(obj.key);
}
// 更好的做法:使用泛型
function identity<T>(value: T): T {
return value;
}
const result = identity("hello");
console.log("结果: " + result);
unknown vs any:unknown 是类型安全的 any,使用前需要进行类型检查。
接口 vs 类型别名
根据场景选择合适的类型定义方式。
实例
interface User {
id: number;
name: string;
}
// 扩展接口
interface User {
email: string;
}
// 类型别名:适合联合类型、元组、函数类型
type ID = string | number;
type Status = "pending" | "success" | "error";
type Callback = (data: string) => void;
// 工具类型通常使用 type
type PartialUser = Partial<User>;
type ReadonlyUser = Readonly<User>;
// 性能考虑:接口的编译速度通常比类型别名快
// 对于简单的对象类型,可以使用 interface
interface Point {
x: number;
y: number;
}
// 对于联合类型,使用 type
type Shape = Circle | Square | Triangle;
选择建议:对象类型使用接口,联合类型使用 type,功能类型使用 type。
构建工具优化
配置构建工具以获得最佳性能。
vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// Vite 配置优化
export default defineConfig({
plugins: [react()],
// 构建优化
build: {
// 启用代码拆分
rollupOptions: {
output: {
// 手动分包
manualChunks: {
'vendor': ['react', 'react-dom'],
'utils': ['lodash', 'axios']
}
}
},
// 压缩代码
minify: 'terser',
// 生成 sourcemap
sourcemap: false,
// 块大小限制
chunkSizeWarningLimit: 500
},
// 开发服务器优化
server: {
// 启用热更新
hmr: {
overlay: true
}
},
// 优化依赖解析
optimizeDeps: {
include: ['react', 'react-dom'],
exclude: ['some-large-library']
}
});
代码分割:使用 manualChunks 将大型库分离,减少主包体积。
Tree Shaking
配置模块以支持 Tree Shaking,消除未使用的代码。
src/utils/index.ts
export function add(a: number, b: number): number {
return a + b;
}
export function subtract(a: number, b: number): number {
return a - b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
export function divide(a: number, b: number): number {
if (b === 0) {
throw new Error("Cannot divide by zero");
}
return a / b;
}
// 具名导出比默认导出更有利于 Tree Shaking
// 错误:export default 会阻止 Tree Shaking
// export default { add, subtract, multiply, divide };
// 正确:使用具名导出
console.log("工具模块加载");
具名导出:使用具名导出而不是默认导出,可以让构建工具更好地进行 Tree Shaking。
注意事项
- skipLibCheck:生产环境必须开启
- 增量编译:开发环境建议开启
- 避免 any:使用 unknown 代替
- Tree Shaking:使用 ES 模块和具名导出
最佳实践:在开发初期就设置好优化配置,避免后期重构。
总结
TypeScript 性能优化涉及多个方面。
- 编译优化:skipLibCheck、incremental、project references
- 类型优化:利用推断、避免 any、选择合适的类型定义
- 构建优化:代码分割、Tree Shaking、依赖优化
- 运行时优化:类型安全、泛型约束
建议:定期检查编译时间和包体积,持续优化项目性能。
