| name | javascript-standards |
| description | JavaScript and TypeScript coding standards, conventions, and best practices. Use when writing, reviewing, or testing JS/TS code. |
JavaScript/TypeScript Coding Standards
New Project Preferences
When starting new frontend projects, prefer:
- React 18 with TypeScript
- Vite for development server
- Parcel for production bundling
- shadcn/ui for components
- Tailwind CSS 3 for styling
General Preferences
- TypeScript over JavaScript for new code
- ESM over CommonJS (
import/export not require)
- Prettier for formatting, ESLint for linting
- Strict TypeScript (
"strict": true in tsconfig)
Style Guide
Formatting (Prettier defaults)
- Line length: 80-100 characters
- Single quotes for strings
- Semicolons: consistent (prefer with)
- Trailing commas: ES5 or all
- 2 space indentation
Naming Conventions
user-service.ts
UserProfile.tsx
const activeUsers = [];
function getUserById(userId: string): User {}
class UserService {}
interface UserProfile {}
type UserId = string;
const MAX_RETRY_ATTEMPTS = 3;
const defaultTimeout = 30000;
function UserCard({ user }: UserCardProps) {}
const ProfileHeader: React.FC<Props> = () => {};
const isActive = true;
const hasPermission = false;
const shouldRefetch = true;
TypeScript
Type Definitions
interface User {
id: string;
email: string;
name: string;
createdAt: Date;
}
type UserId = string | number;
type UserWithPosts = User & { posts: Post[] };
type Readonly<T> = { readonly [K in keyof T]: T[K] };
function parseJSON(json: string): unknown {
return JSON.parse(json);
}
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
Strict Null Checking
function getUser(id: string): User | null {
const user = users.get(id);
return user ?? null;
}
const userName = user?.profile?.name ?? 'Anonymous';
const element = document.getElementById('app')!;
Enums and Constants
const UserRole = {
Admin: 'admin',
User: 'user',
Guest: 'guest',
} as const;
type UserRole = typeof UserRole[keyof typeof UserRole];
enum Status {
Pending = 'pending',
Active = 'active',
Inactive = 'inactive',
}
Functions
const doubled = numbers.map((n) => n * 2);
function processUser(user: User): ProcessedUser {
}
function greet(name: string, greeting = 'Hello'): string {
return `${greeting}, ${name}!`;
}
function createUser({ email, name, role = 'user' }: CreateUserParams): User {
}
function sum(...numbers: number[]): number {
return numbers.reduce((a, b) => a + b, 0);
}
Async Code
async function fetchUserData(userId: string): Promise<UserData> {
const user = await fetchUser(userId);
const posts = await fetchPosts(userId);
return { user, posts };
}
async function fetchAllData(userId: string): Promise<AllData> {
const [user, posts, settings] = await Promise.all([
fetchUser(userId),
fetchPosts(userId),
fetchSettings(userId),
]);
return { user, posts, settings };
}
async function safeOperation(): Promise<Result | null> {
try {
return await riskyOperation();
} catch (error) {
if (error instanceof NetworkError) {
console.(, error.);
;
}
error;
}
}
React Patterns
interface UserCardProps {
user: User;
onEdit?: (user: User) => void;
className?: string;
}
function UserCard({ user, onEdit, className }: UserCardProps) {
return (
<div className={className}>
<h2>{user.name}</h2>
{onEdit && <button onClick={() => onEdit(user)}>Edit</button>}
</div>
);
}
function useUser(userId: string) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
let cancelled = ;
() {
{
data = (userId);
(!cancelled) (data);
} (e) {
(!cancelled) (e );
} {
(!cancelled) ();
}
}
();
{ cancelled = ; };
}, [userId]);
{ user, loading, error };
}
= ( () {
processed = ( (data), [data]);
handleClick = ( (data.), [data., onClick]);
;
});
Error Handling
class AppError extends Error {
constructor(
message: string,
public code: string,
public statusCode: number = 500,
) {
super(message);
this.name = 'AppError';
}
}
class NotFoundError extends AppError {
constructor(resource: string, id: string) {
super(`${resource} with id ${id} not found`, 'NOT_FOUND', 404);
this.name = 'NotFoundError';
}
}
function isAppError(error: unknown): error is AppError {
return error instanceof AppError;
}
function handleError(error: ): {
((error)) {
{ : error., : error. };
}
.(, error);
{ : , : };
}
Testing
import { describe, it, expect, vi, beforeEach } from 'vitest';
describe('UserService', () => {
let service: UserService;
let mockDb: MockDatabase;
beforeEach(() => {
mockDb = createMockDatabase();
service = new UserService(mockDb);
});
it('should fetch user by id', async () => {
mockDb.users.get.mockResolvedValue({ id: '1', name: 'Test' });
const user = await service.getUser('1');
expect(user).toEqual({ id: '1', name: 'Test' });
expect(mockDb.users.get).toHaveBeenCalledWith('1');
});
it('should throw NotFoundError for missing user', async () => {
mockDb.users.get.mockResolvedValue(null);
(service.())..();
});
});
{ render, screen, fireEvent } ;
(, {
(, {
();
(screen.()).();
});
(, {
onEdit = vi.();
();
fireEvent.(screen.(, { : }));
(onEdit).({ : , : });
});
});
Project Commands
Check .claude/commands.md for project-specific commands. Common JS/TS commands:
npm install
npm ci
npm run dev
npm run build
npm run lint
npm run lint -- --fix
npm run format
npm test
npm run test:watch
npm run test:coverage
npm run typecheck
npx tsc --noEmit