typescript-performance
Debug and fix slow TypeScript type checking. Use when tsc or IDE is slow, type checking takes too long, or need to analyze TS compiler performance. Covers diagnostics, tracing, analysis tools, and common fixes.
When & Why to Use This Skill
This Claude skill provides a comprehensive toolkit for diagnosing and resolving TypeScript performance bottlenecks. It enables developers to identify slow type-checking files, analyze compiler traces using tools like @typescript/analyze-trace, and implement targeted optimizations—such as project references, explicit return types, and tsconfig tuning—to significantly reduce build times and improve IDE responsiveness.
Use Cases
- Case 1: Diagnosing slow CI/CD build times by generating and analyzing TypeScript compiler traces to find 'hot spot' files and complex expressions.
- Case 2: Improving IDE responsiveness when autocompletion or type-checking becomes sluggish due to deeply nested generic types or excessively large union types.
- Case 3: Optimizing large-scale monorepos by implementing Project References and configuring incremental builds to minimize redundant compilation cycles.
- Case 4: Identifying and deduplicating multiple versions of the same package in node_modules that cause redundant type identities and increased memory usage.
- Case 5: Troubleshooting 'Out of Memory' errors during compilation by adjusting Node.js heap size and optimizing type inference patterns.
| name | typescript-performance |
|---|---|
| description | Debug and fix slow TypeScript type checking. Use when tsc or IDE is slow, type checking takes too long, or need to analyze TS compiler performance. Covers diagnostics, tracing, analysis tools, and common fixes. |
TypeScript Performance Debugging
Diagnostic Commands
Quick Assessment
# Basic metrics - run multiple times (caching affects results)
tsc --noEmit --extendedDiagnostics
# Key metrics to watch:
# - Check time: Should be <10s for medium projects
# - Instantiations: >1M is a red flag
# - Types: Correlates with complexity
# - Memory used: Watch for >1GB
Generate Trace (Primary Tool)
# Generate trace files for deep analysis
tsc --noEmit --generateTrace ./trace-output
# For memory issues, increase heap
node --max-old-space-size=8192 ./node_modules/.bin/tsc --noEmit --generateTrace ./trace-output
Outputs trace.json and types.json in the output directory.
Trace Analysis
Using @typescript/analyze-trace (Recommended)
npm install --save-dev @typescript/analyze-trace
npx analyze-trace ./trace-output
Output shows hot spots with file locations, line numbers, and time spent. Look for:
- Check file times >1s
- checkExpression operations
- Compare types operations
- Deferred node checks
Options:
--skipMillis=50- lower threshold to see more results--forceMillis=1000- only show items >1s
Simplify Types File
npx simplify-trace-types ./trace-output/types.json output.txt
npx print-trace-types ./trace-output/types.json <type-id>
Visual Analysis
Load trace.json into:
- Perfetto (https://ui.perfetto.dev) - modern, handles large files
- chrome://tracing - built into Chrome
- Speedscope (https://speedscope.app) - better UX
Focus on the "Check" phase in the flame graph - typically 90%+ of total time.
Common Performance Killers
1. Complex Generic Types
Conditional types, mapped types, and deep recursion cause exponential checking:
// BAD: Deeply nested conditional
type DeepPartial<T> = T extends object
? { [P in keyof T]?: DeepPartial<T[P]> }
: T;
// BETTER: Limit recursion depth or use simpler patterns
2. Large Union Types
Union intersection is quadratic:
// BAD: 100+ member unions
type AllEvents = Event1 | Event2 | ... | Event100;
// BETTER: Use base type + discriminator
interface BaseEvent { type: string }
3. Excessive Type Inference
// BAD: Complex inferred return types
export const createStore = () => {
// 50 lines of complex logic
};
// BETTER: Explicit return type annotation
export const createStore = (): Store => { ... };
4. Duplicate Package Versions
analyze-trace warns about this. Different versions = different type identities = no caching. Fix with:
- npm/pnpm
overrides - yarn
resolutions - Dedupe:
npm dedupe/pnpm dedupe
5. Including Too Many Files
// Check what's included
tsc --listFiles
tsconfig.json Optimizations
Quick Wins
{
"compilerOptions": {
"skipLibCheck": true, // Skip .d.ts checking
"incremental": true, // Cache between builds
"tsBuildInfoFile": ".tsbuildinfo"
}
}
For Large Projects
{
"compilerOptions": {
"composite": true, // Required for project refs
"declaration": true,
"declarationMap": true,
"isolatedModules": true // For bundlers (Babel/esbuild)
}
}
Exclude Unnecessary Files
{
"include": ["src/**/*"],
"exclude": [
"node_modules",
"**/*.test.ts",
"**/*.spec.ts",
"dist",
"coverage"
]
}
Limit @types
{
"compilerOptions": {
"types": ["node", "jest"], // Only include what's needed
"typeRoots": ["./node_modules/@types"]
}
}
Project References (Monorepos)
Split large codebase into smaller compilable units:
// Root tsconfig.json
{
"files": [],
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/ui" }
]
}
// packages/core/tsconfig.json
{
"compilerOptions": {
"composite": true,
"declaration": true,
"outDir": "./dist",
"rootDir": "./src"
}
}
Build with: tsc --build or tsc -b
IDE/Editor Performance
VS Code TSServer Logs
- Open Settings, search "typescript trace"
- Set
typescript.tsserver.traceto "verbose" - Open Output panel → TypeScript
Disable Plugins
Test without TS-related extensions to isolate issues.
Workflow
- Baseline:
tsc --noEmit --extendedDiagnostics(run 3x, average) - Trace:
tsc --noEmit --generateTrace ./trace - Analyze:
npx analyze-trace ./trace - Investigate: Focus on top hot spots, check specific files/lines
- Fix: Apply targeted changes
- Verify: Re-run diagnostics, compare metrics
Red Flags in Diagnostics
| Metric | Warning | Critical |
|---|---|---|
| Check time | >15s | >60s |
| Instantiations | >1M | >5M |
| Types | >500K | >1M |
| Memory | >1GB | >4GB |
Quick Fixes Checklist
-
skipLibCheck: true -
incremental: true - Exclude test files from main tsconfig
- Add explicit return type annotations to exported functions
- Deduplicate node_modules packages
- Split into project references if >500 files
- Check for circular dependencies
- Limit union type sizes (<50 members)
- Avoid deeply nested conditional types