typescript-patterns
TypeScript coding style and patterns - type safety, error handling, code organization
When & Why to Use This Skill
This Claude skill provides a comprehensive framework for TypeScript development, focusing on strict type safety, robust error handling, and efficient code organization. It helps developers implement industry-standard patterns like discriminated unions and Result types while avoiding common anti-patterns to ensure high-quality, maintainable, and scalable codebases.
Use Cases
- Standardizing TypeScript codebases: Use these patterns to enforce consistent coding styles and naming conventions across team projects, reducing technical debt and cognitive load.
- Enhancing Type Safety: Systematically identify and replace 'any' or 'unknown' types with precise interfaces, enums, and utility types to catch potential bugs at compile-time.
- Improving Error Resilience: Transition from exception-based error handling to functional Result/Either patterns, ensuring that expected errors are handled explicitly and safely.
- Optimizing Code Architecture: Apply guidelines for function design, async patterns, and file organization to maintain readability and performance as the project grows.
- Automated Quality Audits: Serve as a benchmark for reviewing pull requests to detect anti-patterns like nested ternaries, object mutation, or premature abstraction.
| name | typescript-patterns |
|---|---|
| description | TypeScript coding style and patterns - type safety, error handling, code organization |
Type Safety
- Never use
any- create proper types/enums instead - Avoid
unknowntoo - only use in extreme edge cases where you truly can't know the type - Leverage existing types with
Pick,Omit,Partial,Requiredrather than creating new ones when possible - Use
constassertions for literal types:as const - Discriminated unions for state/variant management
Enums and Constants
- Use enums for related constants, then iterate over them instead of hardcoding values
- Const enums for compile-time optimization
- Object literals with
as constwhen you need both type and runtime access
Error Handling
- Return Result/Either types for expected errors, not exceptions
- Custom error classes with proper typing for unexpected errors
- Validate at boundaries (API, user input) - trust internal types after that
- Early returns for error cases - fail fast, avoid deep nesting
Function Design
- Pure functions when possible - no side effects
- Early returns over nested conditionals
- Function declarations for utilities, arrow functions for callbacks
- Single responsibility as a guideline - use judgment, don't blindly split if it makes code less readable
Code Organization
- Types that are reused across multiple places go in
types/or similar shared location - Types specific to one file/implementation that won't be reused much go at top of file under imports
- Colocate related implementations
- Explicit imports over barrel exports (index files)
- File size guideline is 200-300 lines, but use judgment - split when readability suffers, not by arbitrary line count
Async Patterns
- Always handle Promise rejections
Promise.all()for parallel operations, not sequential awaitsPromise.allSettled()when you need all results regardless of failures- Don't mix callbacks and Promises
Naming Conventions
- Booleans:
isLoading,hasError,canSubmit,shouldRetry - Event handlers:
handleClick,handleSubmit(handler implementations) - Callbacks:
onSubmit,onClick(callback props) - Utilities: verb-first (
formatDate,parseResponse,validateEmail) - Types: PascalCase, purposeful suffixes when needed (
UserResponse,CreateUserDto)
Anti-Patterns to Avoid
- Nested ternaries - use if/else or extract to function
- Object mutation - use spread or immutable updates
- Type assertions (
as) unless absolutely necessary - fix the types properly - Premature abstraction - write it twice before extracting
- Deep nesting - max 2-3 levels, then extract
- Magic numbers/strings - use named constants or enums