TypeScript Refactor Best Practices
Comprehensive TypeScript refactoring and modernization guide designed for AI agents and LLMs. Contains 43 rules across 8 categories, prioritized by impact to guide automated refactoring, code review, and code generation.
When to Apply
Reference these guidelines when:
-
Refactoring TypeScript code for type safety and maintainability
-
Designing type architectures (discriminated unions, branded types, generics)
-
Narrowing types to eliminate unsafe as casts
-
Adopting modern TypeScript 4.x-5.x features (satisfies , using , const type parameters)
-
Optimizing compiler performance in large codebases
-
Implementing type-safe error handling patterns
-
Reviewing code for TypeScript quirks and pitfalls
Rule Categories by Priority
Priority Category Impact Prefix
1 Type Architecture CRITICAL arch-
2 Type Narrowing & Guards CRITICAL narrow-
3 Modern TypeScript HIGH modern-
4 Generic Patterns HIGH generic-
5 Compiler Performance MEDIUM-HIGH compile-
6 Error Safety MEDIUM error-
7 Runtime Patterns MEDIUM perf-
8 Quirks & Pitfalls LOW-MEDIUM quirk-
Quick Reference
- Type Architecture (CRITICAL)
-
arch-discriminated-unions — Use discriminated unions over string enums for exhaustive pattern matching
-
arch-branded-types — Use branded types for domain identifiers to prevent value mix-ups
-
arch-satisfies-over-annotation — Use satisfies for config objects to preserve literal types
-
arch-interfaces-over-intersections — Extend interfaces instead of intersecting types for better error messages
-
arch-const-assertion — Use as const for immutable literal inference
-
arch-readonly-by-default — Default to readonly types for function parameters and return values
-
arch-avoid-partial-abuse — Avoid Partial<T> abuse for builder patterns
- Type Narrowing & Guards (CRITICAL)
-
narrow-custom-type-guards — Write custom type guards instead of type assertions
-
narrow-assertion-functions — Use assertion functions for precondition checks
-
narrow-exhaustive-switch — Enforce exhaustive switch with never
-
narrow-in-operator — Narrow with the in operator for interface unions
-
narrow-eliminate-as-casts — Eliminate as casts with proper narrowing chains
-
narrow-typeof-chains — Use typeof narrowing before property access
- Modern TypeScript (HIGH)
-
modern-using-keyword — Use the using keyword for resource cleanup
-
modern-const-type-parameters — Use const type parameters for literal inference
-
modern-template-literal-types — Use template literal types for string patterns
-
modern-noinfer-utility — Use NoInfer to control type parameter inference
-
modern-accessor-keyword — Use accessor for auto-generated getters and setters
-
modern-verbatim-module-syntax — Enable verbatimModuleSyntax for explicit import types
- Generic Patterns (HIGH)
-
generic-infer-over-annotate — Let TypeScript infer instead of explicit annotation
-
generic-constrain-dont-overconstrain — Constrain generics minimally
-
generic-avoid-distributive-surprises — Control distributive conditional types
-
generic-mapped-type-utilities — Build custom mapped types for repeated transformations
-
generic-return-type-inference — Preserve return type inference in generic functions
- Compiler Performance (MEDIUM-HIGH)
-
compile-explicit-return-types — Add explicit return types to exported functions
-
compile-avoid-deep-recursion — Avoid deeply recursive type definitions
-
compile-project-references — Use project references for monorepo builds
-
compile-base-types-over-unions — Use base types instead of large union types
- Error Safety (MEDIUM)
-
error-result-type — Use Result types instead of thrown exceptions
-
error-exhaustive-error-handling — Use exhaustive checks for typed error variants
-
error-typed-catch — Type catch clause variables as unknown
-
error-never-for-unreachable — Use never to mark unreachable code paths
-
error-discriminated-error-unions — Model domain errors as discriminated unions
- Runtime Patterns (MEDIUM)
-
perf-union-literals-over-enums — Use union literals instead of enums
-
perf-avoid-delete-operator — Avoid the delete operator on objects
-
perf-object-freeze-const — Use Object.freeze with as const for true immutability
-
perf-object-keys-narrowing — Avoid Object.keys type widening
-
perf-map-set-over-object — Use Map and Set over plain objects for dynamic collections
- Quirks & Pitfalls (LOW-MEDIUM)
-
quirk-excess-property-checks — Understand excess property checks on object literals
-
quirk-empty-object-type — Avoid the {} type — it means non-nullish
-
quirk-type-widening-let — Prevent type widening with let declarations
-
quirk-variance-annotations — Use variance annotations for generic interfaces
-
quirk-structural-typing-escapes — Guard against structural typing escape hatches
How to Use
Read individual reference files for detailed explanations and code examples:
-
Section definitions — Category structure and impact levels
-
Rule template — Template for adding new rules
Reference Files
File Description
references/_sections.md Category definitions and ordering
assets/templates/_template.md Template for new rules
metadata.json Version and reference information