Back to skills
SKILL.md
Javascript Patterns
ASecurityJavaScript and TypeScript patterns, anti-patterns, and quality rules — with deterministic regex-based anti-pattern detection for var usage, loose equality (==), leftover console.log, async without await, and common JS pitfalls. Covers Node.js, npm, ESLint, promise patterns, and async code. Use proactively when reviewing JS or TS source files for anti-patterns, running a pre-review scan before ESLint, catching known JS pitfalls, or auditing Node.js or browser codebases. Run the checker for det...
- 13 stars
- 0 votes
- 0 copies
- 0 views
- Added September 5, 2026
Works with
Security analysis
100/100Pro scans all 3 files and shows the line behind each finding
npx -y skills add Everyone-Needs-A-Copilot/claude-copilot --skill javascript-patterns --agent claude-codeAre you the author of Javascript Patterns?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/everyone-needs-a-copilot-javascript-patterns)---
name: javascript-patterns
skill_category: code
description: >-
JavaScript and TypeScript patterns, anti-patterns, and quality rules — with
deterministic regex-based anti-pattern detection for var usage, loose equality
(==), leftover console.log, async without await, and common JS pitfalls.
Covers Node.js, npm, ESLint, promise patterns, and async code. Use proactively
when reviewing JS or TS source files for anti-patterns, running a pre-review
scan before ESLint, catching known JS pitfalls, or auditing Node.js or browser
codebases. Run the checker for deterministic scanning.
version: 2.0.0
source: converted from .claude/skills/code/javascript-patterns.md (2026-05-20); L3 lint-lite checker added
when_to_use:
- Reviewing JavaScript or TypeScript source files for anti-patterns
- Quick pre-review scan before a full ESLint pass
- Catching well-known JS pitfalls (var, ==, leftover console.log)
- Node.js or browser codebase audits
allowed-tools:
- Read
- Grep
- Glob
- Bash
tags: [javascript, typescript, nodejs, patterns, quality, async]
related_skills: [react-patterns, testing-patterns]
trigger_files: ["*.js", "*.ts", "*.mjs", "*.cjs", "package.json", "tsconfig.json"]
trigger_keywords: [javascript, typescript, nodejs, async, promise, eslint, npm]
---
# JavaScript Patterns
Modern JavaScript/TypeScript patterns, anti-patterns, and quality rules.
## Core Principles
| Principle | Description |
|-----------|-------------|
| **Immutability** | Prefer const, avoid mutation |
| **Pure Functions** | Same input = same output, no side effects |
| **Async/Await** | Over raw promises and callbacks |
| **Type Safety** | Use TypeScript for non-trivial projects |
## Patterns vs Anti-Patterns
### Variable Declaration
```typescript
// GOOD: const by default
const config = { timeout: 5000 };
const items = ['a', 'b', 'c'];
// OK: let when reassignment needed
let count = 0;
for (const item of items) {
count++;
}
// BAD: var (hoisting issues)
var data = fetchData(); // Never use var
```
### Async/Await
```typescript
// GOOD: async/await
async function fetchUsers(): Promise<User[]> {
try {
const response = await fetch('/api/users');
return await response.json();
} catch (error) {
throw new ApiError('Failed to fetch users', { cause: error });
}
}
// GOOD: Parallel with Promise.all
const [users, posts] = await Promise.all([
fetchUsers(),
fetchPosts()
]);
// BAD: Sequential when parallel possible
const users = await fetchUsers();
const posts = await fetchPosts(); // Waits unnecessarily
```
### Error Handling
```typescript
// GOOD: Custom error classes
class ValidationError extends Error {
constructor(
message: string,
public field: string,
public code: string
) {
super(message);
this.name = 'ValidationError';
}
}
// GOOD: Error boundary with type narrowing
function isApiError(error: unknown): error is ApiError {
return error instanceof ApiError;
}
try {
await riskyOperation();
} catch (error) {
if (isApiError(error)) {
handleApiError(error);
} else {
throw error; // Re-throw unknown errors
}
}
// BAD: Catch and ignore
try {
await riskyOperation();
} catch (e) {
// Silent failure - never do this
}
```
### Nullish Handling
```typescript
// GOOD: Nullish coalescing
const value = input ?? defaultValue; // Only null/undefined
// GOOD: Optional chaining
const name = user?.profile?.name;
const result = callback?.();
// BAD: OR for defaults (falsy issues)
const value = input || defaultValue; // 0, '', false become default!
// BAD: Manual null checks
const name = user && user.profile && user.profile.name;
```
### Array Methods
```typescript
// GOOD: Functional array methods
const activeUsers = users
.filter(u => u.active)
.map(u => ({ id: u.id, name: u.name }));
// GOOD: find/findIndex for single items
const admin = users.find(u => u.role === 'admin');
const index = users.findIndex(u => u.id === targetId);
// GOOD: reduce for accumulation
const byId = users.reduce((acc, user) => {
acc[user.id] = user;
return acc;
}, {} as Record<string, User>);
// BAD: forEach with mutation
const results = [];
users.forEach(u => {
if (u.active) results.push(u.name);
});
```
### Object Operations
```typescript
// GOOD: Spread for immutable updates
const updated = { ...user, name: 'New Name' };
const merged = { ...defaults, ...options };
// GOOD: Destructuring
const { id, name, email } = user;
const { data, error } = await fetchUser(id);
// GOOD: Computed property names
const key = 'dynamicKey';
const obj = { [key]: value };
// BAD: Object.assign mutation
Object.assign(user, { name: 'New Name' }); // Mutates!
```
### String Operations
```typescript
// GOOD: Template literals
const message = `Hello, ${name}! You have ${count} items.`;
const multiline = `
First line
Second line
`;
// GOOD: Tagged templates for escaping
const query = sql`SELECT * FROM users WHERE id = ${userId}`;
// BAD: Concatenation
const message = 'Hello, ' + name + '!';
```
## Anti-Patterns to Avoid
### Type Coercion Issues
```typescript
// BAD: Implicit coercion
if (value == null) { } // Catches both null and undefined
const str = '' + num; // Use String(num)
// GOOD: Explicit comparison
if (value === null || value === undefined) { }
if (value == null) { } // OK - intentional loose equality for null/undefined
// GOOD: Explicit conversion
const str = String(num);
const num = Number(str);
const bool = Boolean(value);
```
### Callback Hell
```typescript
// BAD: Nested callbacks
getData((data) => {
process(data, (result) => {
save(result, (saved) => {
notify(saved, () => {
console.log('Done');
});
});
});
});
// GOOD: async/await
const data = await getData();
const result = await process(data);
const saved = await save(result);
await notify(saved);
```
### Floating Promises
```typescript
// BAD: Unhandled promise
fetchData(); // Fire and forget - errors lost!
// GOOD: Handle or await
await fetchData();
// OR
fetchData().catch(handleError);
// OR
void fetchData(); // Explicit discard (use sparingly)
```
### `this` Binding Issues
```typescript
// BAD: Lost context
class Handler {
name = 'Handler';
handleClick() {
console.log(this.name); // undefined when used as callback!
}
}
// GOOD: Arrow function or bind
class Handler {
name = 'Handler';
handleClick = () => {
console.log(this.name); // Works!
};
}
```
## TypeScript Best Practices
### Type Definitions
```typescript
// GOOD: Interface for objects
interface User {
id: string;
name: string;
email: string;
}
// GOOD: Type alias for unions/primitives
type Status = 'pending' | 'active' | 'archived';
type ID = string | number;
// GOOD: Generics for reusable types
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
```
### Type Guards
```typescript
// Discriminated unions
interface SuccessResponse { status: 'success'; data: unknown }
interface ErrorResponse { status: 'error'; message: string }
type Response = SuccessResponse | ErrorResponse;
function handleResponse(res: Response) {
if (res.status === 'success') {
// TypeScript knows res.data exists
return res.data;
} else {
// TypeScript knows res.message exists
throw new Error(res.message);
}
}
```
### Avoid `any`
```typescript
// BAD: any disables type checking
function process(data: any): any { }
// GOOD: unknown + type guard
function process(data: unknown): Result {
if (isValidData(data)) {
return transform(data);
}
throw new ValidationError('Invalid data');
}
```
## Quality Checklist
| Check | Rule |
|-------|------|
| No `var` | Use `const` by default, `let` when needed |
| No `any` | Use `unknown` with type guards |
| Async/await | Over raw promises |
| Nullish ops | `??` and `?.` over `||` and `&&` |
| Immutable | Spread over mutation |
| Type safety | All exports typed |
| Error handling | No silent catches |
| No floating promises | Always handle or await |
## Invocation — JavaScript Anti-Pattern Checker (L3 Script)
Run the checker on any JavaScript or TypeScript source file. Consume its **output only** — the script source never enters context.
**Scope note:** This is a regex-based lint-lite tool, not a full AST parser. It reliably catches the named closed-set patterns (var declarations, loose equality, leftover debug calls, callback nesting depth). It does NOT replace ESLint — use ESLint for comprehensive coverage. Treat its findings as confirmed anti-patterns; treat its silence as "none of these specific patterns found."
**Run via Bash (file argument):**
```bash
python .claude/skills/code/javascript-patterns/scripts/js_patterns.py path/to/file.js
```
**Run via Bash (stdin — paste code or pipe):**
```bash
cat path/to/file.ts | python .claude/skills/code/javascript-patterns/scripts/js_patterns.py -
```
**The script outputs:**
1. A JSON object with `findings` (list of anti-patterns with rule, severity, line, message) and a `summary` of counts by severity.
2. A human-readable markdown table sorted by severity descending.
**Detected rules:**
- `VAR_DECL` MEDIUM — `var` declaration (use const/let)
- `LOOSE_EQUALITY` MEDIUM — `==` or `!=` operator (use `===`/`!==`)
- `CONSOLE_LOG` LOW — leftover `console.log(` call
- `CALLBACK_NESTING` MEDIUM — callback nesting depth >= 3 (likely callback hell)
**Error handling:** Script exits 1 on unreadable file. Exits 0 even if findings are present.
**What the agent does with the output:**
1. Raise MEDIUM findings in code review comments.
2. LOW findings (console.log) flag debug code left in — ask author to remove before merge.
3. CALLBACK_NESTING findings suggest refactoring to async/await.
Files in this skill
- SKILL.md
- scripts/js_patterns.py
- scripts/test_js_patterns.py
Attribution
Comments
Loading comments…