Performance
3 min readRapid overview
- TypeScript Performance Optimization
- TypeScript Compiler Performance
- Compilation Speed
- Type Performance
- Runtime Performance
- Type Assertions vs Type Guards
- Const Enums (Inlined)
- Generic Type Constraints
- Build Optimization
- Tree Shaking
- Barrel Files Consideration
- Type-Safe Performance Patterns
- Memoization with Types
- Typed Lazy Loading
- Best Practices
- Measuring TypeScript Compilation
- Performance Tips
TypeScript Performance Optimization
Performance considerations specific to TypeScript development.
TypeScript Compiler Performance
Compilation Speed
Project References:
// tsconfig.json
{
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/ui" }
]
}
Incremental Compilation:
// tsconfig.json
{
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./.tsbuildinfo"
}
}
Skip Lib Check:
{
"compilerOptions": {
"skipLibCheck": true // Faster builds
}
}
Type Performance
Avoid Complex Type Unions:
// ❌ Slow - large union
type Status = 'idle' | 'pending' | 'success' | 'error' | /* 100 more */;
// ✅ Fast - use enums or const assertions
const Status = {
IDLE: 'idle',
PENDING: 'pending',
SUCCESS: 'success',
ERROR: 'error'
} as const;
type StatusType = typeof Status[keyof typeof Status];
Prefer Interfaces Over Types for Objects:
// ✅ Faster for extending
interface User {
name: string;
age: number;
}
interface Employee extends User {
role: string;
}
Runtime Performance
Type Assertions vs Type Guards
// Type assertion (no runtime cost)
const value = someValue as string;
// Type guard (runtime cost, but safer)
function isString(value: unknown): value is string {
return typeof value === 'string';
}
if (isString(value)) {
// TypeScript knows value is string
console.log(value.toUpperCase());
}
Const Enums (Inlined)
// ❌ Regular enum (generates runtime code)
enum Direction {
Up,
Down,
Left,
Right
}
// ✅ Const enum (inlined at compile time, no runtime cost)
const enum Direction {
Up,
Down,
Left,
Right
}
// Compiled output uses literal values
Generic Type Constraints
// More specific constraints = better performance hints
function process<T extends { id: number }>(item: T): number {
return item.id; // TypeScript knows id exists
}
Build Optimization
Tree Shaking
// ✅ Use ES modules for tree shaking
export const utilA = () => { /* ... */ };
export const utilB = () => { /* ... */ };
// Import only what you need
import { utilA } from './utils';
Barrel Files Consideration
// ❌ Can hurt tree shaking
// index.ts
export * from './moduleA';
export * from './moduleB';
export * from './moduleC';
// ✅ Better - direct imports
import { functionA } from './moduleA';
Type-Safe Performance Patterns
Memoization with Types
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) => {
// Heavy computation
return n * 2;
});
Typed Lazy Loading
type LazyModule<T> = () => Promise<{ default: T }>;
async function loadComponent<T>(loader: LazyModule<T>): Promise<T> {
const module = await loader();
return module.default;
}
// Usage
const MyComponent = await loadComponent(() => import('./MyComponent'));
Best Practices
- Use
strictNullChecks- Catches potential runtime errors at compile time - Enable
noImplicitAny- Prevents accidental type holes - Use Project References - For large monorepos
- Leverage Incremental Compilation - Faster rebuilds
- Const Enums - When you don't need runtime enum objects
- Type-Only Imports - For better tree shaking
- Avoid Deep Type Recursion - Can slow down compilation
// Type-only imports (removed at runtime)
import type { User } from './types';
Measuring TypeScript Compilation
# Measure compilation time
tsc --diagnostics
# Extended diagnostics
tsc --extendedDiagnostics
# List files being compiled
tsc --listFiles
Performance Tips
- Use
constassertions for literal types - Prefer
interfaceovertypefor object shapes - Use mapped types judiciously
- Avoid excessive type generics
- Use discriminated unions for better type narrowing
- Enable
skipLibCheckfor faster builds - Use project references for large codebases