Skip to main content

Code Style Guide

Coding conventions and best practices.

General Principles

  1. Readability first - Code is read more than written
  2. Consistency - Follow established patterns
  3. Simplicity - Prefer simple over clever
  4. Self-documenting - Clear names over comments

TypeScript

Naming Conventions

// Variables and functions: camelCase
const userName = 'John';
function getUserName() {}

// Classes and types: PascalCase
class UserService {}
type UserProfile = {};
interface UserData {}

// Constants: SCREAMING_SNAKE_CASE
const MAX_RETRIES = 3;

// Files: kebab-case
// user-service.ts
// get-user-data.ts

Functions

// Prefer arrow functions for callbacks
const numbers = [1, 2, 3].map((n) => n * 2);

// Use regular functions for methods
function calculateTotal(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}

// Destructure parameters
function createUser({ name, email }: CreateUserInput) {
// ...
}

Types

// Prefer interfaces for objects
interface User {
id: string;
name: string;
email: string;
}

// Use types for unions and utilities
type Status = 'pending' | 'active' | 'inactive';
type UserWithPosts = User & { posts: Post[] };

// Always type function parameters and returns
function getUser(id: string): Promise<User | null> {
// ...
}

React

Component Structure

// 1. Imports
import { useState } from 'react';
import { Button } from '@/components/ui/button';

// 2. Types
interface UserCardProps {
user: User;
onEdit: (id: string) => void;
}

// 3. Component
export function UserCard({ user, onEdit }: UserCardProps) {
// 3a. Hooks
const [isLoading, setIsLoading] = useState(false);

// 3b. Handlers
const handleEdit = () => {
onEdit(user.id);
};

// 3c. Render
return (
<div className="p-4 border rounded">
<h3>{user.name}</h3>
<Button onClick={handleEdit}>Edit</Button>
</div>
);
}

Naming

// Components: PascalCase
function UserProfile() {}

// Hooks: use prefix
function useUserData() {}

// Event handlers: handle prefix
const handleClick = () => {};
const handleSubmit = () => {};

File Organization

src/
├── app/ # Routes/pages
├── components/
│ ├── ui/ # Base UI components
│ └── features/ # Feature-specific components
├── lib/
│ ├── utils.ts # Utility functions
│ └── constants.ts # Shared constants
├── services/ # API/external services
├── hooks/ # Custom hooks
└── types/ # Shared types

Comments

// Good: Explain WHY, not WHAT
// Retry with exponential backoff to handle rate limiting
const delay = Math.pow(2, attempt) * 1000;

// Bad: Describes what code already says
// Increment counter by 1
counter++;

// Use TODO for future work
// TODO: Implement caching for better performance

Error Handling

// Always handle errors explicitly
try {
const result = await fetchUser(id);
return result;
} catch (error) {
console.error('Failed to fetch user:', error);
throw new UserFetchError('Unable to fetch user', { cause: error });
}

// Use custom error classes
class UserFetchError extends Error {
constructor(message: string, options?: ErrorOptions) {
super(message, options);
this.name = 'UserFetchError';
}
}

Imports

// Order: external, internal, relative
import { useState } from 'react'; // 1. External
import { cn } from '@/lib/utils'; // 2. Internal (alias)
import { Button } from '../components/Button'; // 3. Relative

Formatting

  • Use Prettier for automatic formatting
  • 2 space indentation
  • Single quotes for strings
  • Trailing commas
  • No semicolons (or always - pick one)
// .prettierrc
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5"
}