Module 27: Performance Optimization
Learn performance optimization techniques for TypeScript applications including compilation, runtime performance, and bundle size reduction.
1. Compilation Performance
// tsconfig.json
{
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": ".tsbuildinfo",
"skipLibCheck": true,
"skipDefaultLibCheck": true
}
}
2. Tree Shaking
// utils.ts - Use named exports
export const add = (a: number, b: number) => a + b;
export const multiply = (a: number, b: number) => a * b;
// app.ts - Import only what you need
import { add } from "./utils"; // multiply will be tree-shaken
3. Code Splitting
// Dynamic imports
async function loadFeature() {
const module = await import("./feature");
module.initialize();
}
// React lazy loading
const Dashboard = React.lazy(() => import("./Dashboard"));
4. Memoization
function memoize<T extends (...args: any[]) => any>(fn: T): T {
const cache = new Map();
return ((...args: Parameters<T>): ReturnType<T> => {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn(...args);
cache.set(key, result);
return result;
}) as T;
}
const expensiveCalculation = memoize((n: number): number => {
console.log("Computing...");
return n * 2;
});
5. Lazy Evaluation
class LazyValue<T> {
private value?: T;
private computed = false;
constructor(private compute: () => T) {}
get(): T {
if (!this.computed) {
this.value = this.compute();
this.computed = true;
}
return this.value!;
}
}
const lazy = new LazyValue(() => {
console.log("Computing expensive value...");
return 42;
});
// Value computed only when accessed
console.log(lazy.get());
6. Object Pool Pattern
class ObjectPool<T> {
private available: T[] = [];
private inUse = new Set<T>();
constructor(
private factory: () => T,
private reset: (obj: T) => void,
initialSize: number = 10
) {
for (let i = 0; i < initialSize; i++) {
this.available.push(this.factory());
}
}
acquire(): T {
let obj = this.available.pop();
if (!obj) {
obj = this.factory();
}
this.inUse.add(obj);
return obj;
}
release(obj: T): void {
if (this.inUse.has(obj)) {
this.inUse.delete(obj);
this.reset(obj);
this.available.push(obj);
}
}
}
7. Debounce and Throttle
function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let timeoutId: NodeJS.Timeout;
return (...args: Parameters<T>) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn(...args), delay);
};
}
function throttle<T extends (...args: any[]) => any>(
fn: T,
limit: number
): (...args: Parameters<T>) => void {
let inThrottle: boolean;
return (...args: Parameters<T>) => {
if (!inThrottle) {
fn(...args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
8. Virtual Scrolling
interface VirtualScrollProps<T> {
items: T[];
itemHeight: number;
containerHeight: number;
renderItem: (item: T) => React.ReactNode;
}
function VirtualScroll<T>({ items, itemHeight, containerHeight, renderItem }: VirtualScrollProps<T>) {
const [scrollTop, setScrollTop] = useState(0);
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(
startIndex + Math.ceil(containerHeight / itemHeight),
items.length
);
const visibleItems = items.slice(startIndex, endIndex);
const totalHeight = items.length * itemHeight;
const offsetY = startIndex * itemHeight;
return (
<div
style={{ height: containerHeight, overflow: "auto" }}
onScroll={(e) => setScrollTop(e.currentTarget.scrollTop)}
>
<div style={{ height: totalHeight, position: "relative" }}>
<div style={{ transform: `translateY(${offsetY}px)` }}>
{visibleItems.map(renderItem)}
</div>
</div>
</div>
);
}
9. Worker Threads
// worker.ts
self.onmessage = (e: MessageEvent) => {
const result = expensiveCalculation(e.data);
self.postMessage(result);
};
// main.ts
const worker = new Worker("worker.js");
worker.postMessage(data);
worker.onmessage = (e) => {
console.log("Result:", e.data);
};
10. Bundle Analysis
# Webpack Bundle Analyzer
npm install --save-dev webpack-bundle-analyzer
# Run analysis
npx webpack-bundle-analyzer dist/stats.json
Key Takeaways
✅ Incremental compilation speeds up builds
✅ Tree shaking removes unused code
✅ Code splitting reduces initial load
✅ Memoization caches results
✅ Virtual scrolling for large lists
✅ Worker threads for CPU-intensive tasks
Practice Exercises
Exercise 1: Implement LRU Cache
class LRUCache<K, V> {
private cache = new Map<K, V>();
constructor(private capacity: number) {}
get(key: K): V | undefined {
// Implementation
}
set(key: K, value: V): void {
// Implementation
}
}
Exercise 2: Performance Monitoring
Create a performance monitoring decorator for functions.
Next Steps
In Module 28, we'll explore Error Handling Best Practices for robust TypeScript applications.