
typescript-performance
by robBowes
SKILL.md
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
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon