Ts Performance
π
2026-06-23 | π TypeScript
TypeScript project performance optimization involves compilation speed, runtime performance, and code size.
This tutorial introduces common performance optimization techniques to help build more efficient TypeScript applications.
* * *
* * *
## Why Performance Optimization is Needed
While TypeScript provides a powerful type system, improper use can affect compilation speed and runtime performance.
Compilation of large projects may take several minutes, severely impacting the development experience.
The configurations and techniques introduced in this tutorial can significantly improve the performance of TypeScript projects.
> **Optimization Goals:** Faster compilation speed, smaller bundle size, higher runtime performance.
* * *
## Compilation Configuration Optimization
Improve compilation speed by optimizing tsconfig.json configuration.
## tsconfig.json Optimization
```json
{
"compilerOptions": {
// Enable incremental compilation, save previous compilation info
"incremental": true,
// Skip type checking of node_modules
// Greatly improves compilation speed
"skipLibCheck": true,
// Skip declaration file generation (only generate in final build)
"noEmit": true,
// Enable fast incremental builds
"assumeChangesOnlyAffectDirectDependencies": true,
// Execute in parallel
"parallel": true,
// Enable caching
"tsBuildInfoFile": ".tsbuildinfo",
// Files that don't need to be resolved
"exclude": [
"node_modules",
"dist",
"build",
"**/*.test.ts"
]
}
}
> **skipLibCheck:** This is the most important optimization option, which can reduce compilation time by more than 50%.
* * *
## Project References Optimization
Use project references to split large projects into smaller modules, enabling incremental compilation.
## packages/utils/tsconfig.json
```json
{
// Inherit base configuration
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"outDir": "./dist",
"declaration": true,
"declarationMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
> **composite:** When enabled, TypeScript generates .tsbuildinfo files to accelerate subsequent compilations.
* * *
## Type Inference Optimization
Make full use of TypeScript's type inference and avoid excessive annotations.
Example
```typescript
// Bad practice: excessive type annotations
const name: string = "Alice";
const age: number = 25;
const isActive: boolean = true;
// Good practice: use type inference
const name = "Alice";
const age = 25;
const isActive = true;
// Function return type can be omitted (TypeScript infers automatically)
function add(a: number, b: number) {
return a + b;
}
// Complex objects use type inference
const user = {
id: 1,
name: "Bob",
email: "bob@example.com"
};
// TypeScript infers:
// { id: number; name: string; email: string }
// Only explicitly annotate when type inference is inaccurate
const elements: HTMLElement[] = [];
> **Reduce annotations:** TypeScript's type inference is already very intelligent; in most cases explicit type annotations are not needed.
* * *
## Avoid Using any
Using any loses the advantages of type checking and affects runtime performance.
## Example
```typescript
// Bad practice: using any
function processData(data: any): any {
return data.value;
}
// Good practice: use unknown or specific types
function processData(data: T): string {
return data.value;
}
// If you really don't know the type, use unknown
function parseJSON(json: string): unknown {
return JSON.parse(json);
}
// Perform type checking when using
const data = parseJSON('{"key": "value"}');
if (typeof data === "object" && data !== null) {
const obj = data as { key: string };
console.log(obj.key);
}
// Better approach: use generics
function identity(value: T): T {
return value;
}
const result = identity("hello");
console.log("Result: " + result);
> **unknown vs any:** unknown is a type-safe any; type checking is required before use.
* * *
## Interface vs Type Alias
Choose the appropriate type definition method based on the scenario.
## Example
```typescript
// Interface: suitable for defining object types, supports declaration merging
interface User {
id: number;
name: string;
}
// Extending interface
interface User {
email: string;
}
// Type alias: suitable for union types, tuples, function types
type ID = string | number;
type Status = "pending" | "success" | "error";
type Callback = (data: string) => void;
// Utility types usually use type
type PartialUser = Partial;
type ReadonlyUser = Readonly;
// Performance consideration: interfaces usually compile faster than type aliases
// For simple object types, use interface
interface Point {
x: number;
y: number;
}
// For union types, use type
type Shape = Circle | Square | Triangle;
> **Selection suggestion:** Use interface for object types, type for union types, and type for function types.
* * *
## Build Tool Optimization
Configure build tools for optimal performance.
## vite.config.ts
```typescript
// Import vite
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// Vite configuration optimization
export default defineConfig({
plugins: [react()],
// Build optimization
build: {
// Enable code splitting
rollupOptions: {
output: {
// Manual chunk splitting
manualChunks: {
'vendor': ['react', 'react-dom'],
'utils': ['lodash', 'axios']
}
}
},
// Minify code
minify: 'terser',
// Generate sourcemap
sourcemap: false,
// Chunk size limit
chunkSizeWarningLimit: 500
},
// Development server optimization
server: {
// Enable hot module replacement
hmr: {
overlay: true
}
},
// Optimize dependency resolution
optimizeDeps: {
include: ['react', 'react-dom'],
exclude: ['some-large-library']
}
});
> **Code splitting:** Use manualChunks to separate large libraries and reduce main bundle size.
* * *
## Tree Shaking
Configure modules to support Tree Shaking, eliminating unused code.
## src/utils/index.ts
```typescript
// Use ES module exports to support Tree Shaking
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;
}
// Named exports are more conducive to Tree Shaking than default exports
// Wrong: export default prevents Tree Shaking
// export default { add, subtract, multiply, divide };
// Correct: use named exports
console.log("Utility module loaded");
> **Named exports:** Use named exports instead of default exports to allow build tools to better perform Tree Shaking.
* * *
## Notes
* **skipLibCheck:** Must be enabled in production environment
* **Incremental compilation:** Recommended to enable in development environment
* **Avoid any:** Use unknown instead
* **Tree Shaking:** Use ES modules and named exports
> **Best practice:** Set up optimization configurations early in development to avoid later refactoring.
* * *
## Summary
TypeScript performance optimization involves multiple aspects.
* **Compilation optimization:** skipLibCheck, incremental, project references
* **Type optimization:** leverage inference, avoid any, choose appropriate type definitions
* **Build optimization:** code splitting, Tree Shaking, dependency optimization
* **Runtime optimization:** type safety, generic constraints
> **Suggestion:** Regularly check compilation time and bundle size, continuously optimize project performance.