Awesome-omni-skill js-ts-best-practices
JavaScript and TypeScript best practices covering naming conventions, control flow, state management, TypeScript patterns (avoid any/enum, prefer type over interface), safety (input validation, assertions, error handling), performance optimization (reduce branching/looping, memoization, defer await, cache property access, storage API caching), and documentation (JSDoc, comment markers). Use when writing JS/TS functions, refactoring code for performance, reviewing code quality, fixing type errors, optimizing loops or conditionals, adding validation, or improving error messages.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/development/js-ts-best-practices" ~/.claude/skills/diegosouzapw-awesome-omni-skill-js-ts-best-practices-7fbcbf && rm -rf "$T"
skills/development/js-ts-best-practices/SKILL.mdJavaScript and TypeScript Best Practices
Comprehensive coding standards and performance optimization guide for JavaScript and TypeScript applications, designed for AI agents and LLMs working with modern JavaScript/TypeScript codebases.
When to Activate This Skill
Use this skill when the task involves:
Writing JavaScript/TypeScript Code
- Creating new functions, classes, or modules
- Implementing control flow logic (conditionals, loops, early returns)
- Managing state with variables (
vsconst
)let - Writing TypeScript type definitions, interfaces, or generics
- Defining enums or constant objects
- Structuring code with proper naming conventions
TypeScript-Specific Tasks
- Fixing type errors or improving type safety
- Replacing
with proper types (any
, generics)unknown - Converting
toenum
objectsas const - Choosing between
andtypeinterface - Adding type annotations to untyped code
- Implementing generic functions or utilities
Code Quality & Style
- Refactoring nested conditionals to early returns
- Simplifying complex control flow
- Improving variable naming (descriptive names, proper prefixes for booleans)
- Reducing code duplication
- Applying consistent code style
- Removing commented-out code or outdated comments
Safety & Validation
- Adding input validation at system boundaries
- Implementing assertions for programmer error detection
- Improving error handling patterns
- Writing better error messages (user-facing or developer-facing)
- Validating external data with schemas (Zod, etc.)
- Preventing null/undefined propagation
Performance Optimization
- Reducing unnecessary branching or conditionals
- Optimizing array operations (reduce instead of chained filter/map)
- Implementing efficient data structures (Set vs Array for lookups)
- Caching expensive computations or API calls
- Optimizing loops (cache property access, array length)
- Deferring
operations to avoid blockingawait - Caching
,localStorage
, or cookie readssessionStorage
Documentation
- Adding JSDoc comments to exported functions
- Using proper comment markers (TODO, FIXME, HACK, NOTE, PERF)
- Removing unnecessary comments
- Preserving important comments (business logic, linter directives)
- Documenting function parameters, return types, and examples
Code Review
- Reviewing code for style violations
- Identifying performance anti-patterns
- Checking for safety issues (missing validation, poor error handling)
- Ensuring TypeScript best practices
- Verifying proper documentation
When NOT to Use This Skill
Do not activate for:
- Framework-specific code (React, Vue, Angular) - use framework-specific skills instead
- Node.js-specific APIs or server-side concerns (unless general JS/TS patterns apply)
- Build tooling configuration (webpack, vite, tsconfig.json) unless code quality-related
- Testing code (use a testing-specific skill if available)
- Database queries or ORM usage
- CSS, HTML, or styling (unless embedded in JS/TS files)
- Package management (npm, yarn, pnpm)
How to Use
This skill uses a progressive disclosure structure to minimize context usage:
1. Start with the Overview (AGENTS.md)
Read AGENTS.md for a concise overview of all rules with one-line summaries organized by category.
2. Load Specific Rules as Needed
When you identify a relevant pattern or issue, load the corresponding reference file for detailed implementation guidance:
General Best Practices:
- naming-conventions.md - Descriptive names, qualifier ordering, boolean prefixes
- functions.md - Function size, parameters, explicit values
- control-flow.md - Early returns, flat structure, block style
- state-management.md - const vs let, immutability, pure functions
- return-values.md - Return zero values instead of null/undefined
- misc.md - Line endings, defensive programming, technical debt
TypeScript:
- any.md - Avoid any, use unknown or generics
- enums.md - Use as const objects instead of enum
- type-vs-interface.md - Prefer type over interface
Safety:
- input-validation.md - Validate external data with schemas
- assertions.md - Split assertions, include values
- error-handling.md - Handle all errors explicitly
- error-messages.md - User-friendly vs developer-specific messages
Performance:
- reduce-branching.md - Use lookup tables instead of conditionals
- reduce-looping.md - reduce vs chained methods, Set.has() vs Array.includes()
- memoization.md - When to memoize (avoid trivial computations)
- batching.md - Batch I/O operations
- predictable-execution.md - Clear execution paths for CPU caching
- bounded-iteration.md - Set limits on loops and queues
- defer-await.md - Move await into branches that need it
- cache-property-access.md - Cache object lookups in loops
- cache-storage-api.md - Cache localStorage/sessionStorage/cookie reads
Documentation:
- jsdoc.md - Well-formed JSDoc for exports
- comment-markers.md - TODO, FIXME, HACK, NOTE markers
- comments-to-remove.md - Commented code, edit history
- comments-to-preserve.md - Markers, linter directives, business logic
- comments-placement.md - Move end-of-line comments above code
3. Apply the Pattern
Each reference file contains:
- ❌ Incorrect examples showing the anti-pattern
- ✅ Correct examples showing the optimal implementation
- Explanations of why the pattern matters
Examples
Example 1: Optimizing Array Operations
Task: "This filter().map() chain is slow on large arrays"
Approach:
- Read AGENTS.md overview
- Identify issue: multiple iterations over same array
- Load reduce-looping.md
- Replace chained methods with single reduce() call
Before:
const result = items.filter(x => x.active).map(x => x.id);
After:
const result = items.reduce((acc, x) => x.active ? [...acc, x.id] : acc, [] );
Example 2: Fixing TypeScript any
Usage
anyTask: "Replace
any types with proper TypeScript types"
Approach:
- Read AGENTS.md overview
- Identify need for type safety
- Load any.md
- Replace
withany
or generics based on use caseunknown
Before:
function process(data: any): any { /**/ }
After:
function process<T>(data: T): Result<T> { /**/ } // or function process(data: unknown): User { /**/ }
Example 3: Improving Error Messages
Task: "Make error messages more helpful for users"
Approach:
- Read AGENTS.md overview
- Identify need for better error messaging
- Load error-messages.md
- Replace technical errors with user-friendly, actionable messages
Before:
throw new Error('500');
After:
alert( 'We\'re having trouble connecting to our server.\n' + 'Please check your internet connection and try again.' );
Example 4: Caching Storage API Calls
Task: "This function calls localStorage.getItem() 100 times in a loop"
Approach:
- Read AGENTS.md overview
- Identify performance issue: repeated storage reads
- Load cache-storage-api.md
- Implement Map-based cache with invalidation strategy
Before:
for (const item of items) { const theme = localStorage.getItem('theme'); // ... 100 storage reads }
After:
const storageCache = new Map(); function getCached(key) { if (!storageCache.has(key)) { storageCache.set(key, localStorage.getItem(key)); } return storageCache.get(key); } for (const item of items) { const theme = getCached('theme'); // ... 1 storage read }
Important Notes
Performance Philosophy
Design for performance from the start. Optimize slowest resources first:
network >> disk >> memory >> cpu
Always benchmark your assumptions before moving on. Premature optimization of CPU-bound operations while ignoring network bottlenecks wastes time.
State Management Principles
- Prefer
: Useconst
only for valid performance reasonslet - Immutability: Never mutate passed references; create copies
- Pure functions: Keep leaf functions pure; centralize state in parents
- Zero values: Return
,[]
,{}
,0
instead of''
/nullundefined
TypeScript Best Practices
- Avoid
: Useany
for truly unknown types, generics for flexibilityunknown - Avoid
: Useenum
objects for better tree-shaking and type inferenceas const - Prefer
: Usetype
only for declaration merging or class contractsinterface
Code Quality Principles
- Functions under 50 lines: Break down large functions
- Early returns: Prefer flat control flow over nested conditionals
- Descriptive names: Use complete words, append qualifiers in descending order
- Explicit values: Avoid default parameters; make all values explicit at call site
Safety First
- Validate at boundaries: All external data must be validated (user input, API responses)
- Assertions for programmer errors: Crash on corrupted code state
- Split compound assertions: One assertion per invariant
- Include values in messages: Always show actual vs expected values
Documentation Standards
- All exports need JSDoc: Minimum
,@param
,@returns@example - Use comment markers: TODO, FIXME, HACK, NOTE, REVIEW, PERF
- Remove dead code: No commented-out code or edit history
- Preserve business logic: Keep comments explaining "why", not "what"
Optimization Strategies
When optimizing performance:
- Measure first: Use profiling tools to identify actual bottlenecks
- Network first: Optimize network requests before code execution
- Reduce iterations: Single reduce() instead of chained filter().map()
- Cache lookups: Use Set for O(1) membership checks, cache property access in loops
- Defer work: Move expensive operations (await, computation) into branches that need them
- Batch operations: Group I/O operations to reduce overhead
- Predictable paths: Write code with clear execution flow for CPU optimization
Additional Context
When Functions Are Too Small
Some patterns (like lookup tables) may seem to violate the "no premature optimization" principle. These are architectural choices, not optimizations:
- Lookup tables improve maintainability (add entries without new conditionals)
- Early returns reduce cognitive load (fewer nested levels)
- Const over let prevents accidental mutations (correctness, not speed)
Defensive Programming
This skill emphasizes "negative-space" or defensive programming:
- Return zero values to eliminate downstream null checks
- Assert invariants to catch bugs early
- Validate at boundaries to contain invalid data
- Handle all errors explicitly (no silent failures)
The goal is correctness first, performance second.