Code Style Guide
Coding standards and best practices for the AI Store project.
General Principles
Readability First
Code should be easy to read and understand:
// Good: Clear and readable
const userCount = users.length;
const hasUsers = userCount > 0;
// Bad: Unclear
const uc = u.length;
const hu = uc > 0;
Consistency
Follow consistent patterns throughout the codebase:
// Good: Consistent naming
const handleSubmit = () => {};
const handleChange = () => {};
const handleClick = () => {};
// Bad: Inconsistent
const submit = () => {};
const onChange = () => {};
const clickHandler = () => {};
Naming Conventions
Variables and Functions
// camelCase for variables and functions
const userName = 'John';
const getUserData = () => {};
// Descriptive names
const isUserLoggedIn = true;
const fetchUserProfile = async () => {};
Components
// PascalCase for components
export default function UserProfile() {}
export function UserCard() {}
Constants
// UPPER_SNAKE_CASE for constants
const MAX_FILE_SIZE = 10 * 1024 * 1024;
const API_BASE_URL = 'https://api.example.com';
Types and Interfaces
// PascalCase for types
type User = {
id: string;
name: string;
};
interface UserProfile {
user: User;
settings: Settings;
}
File Organization
File Naming
components/
UserProfile.tsx # Component
useUserData.ts # Hook
userUtils.ts # Utility
types.ts # Types
File Structure
// 1. Imports
import React from 'react';
import { useState } from 'react';
// 2. Types
type Props = {
userId: string;
};
// 3. Component
export default function Component({ userId }: Props) {
// Component logic
return <div>Content</div>;
}
TypeScript
Type Safety
// Good: Explicit types
function calculateTotal(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
// Bad: Any types
function calculateTotal(items: any[]): any {
return items.reduce((sum: any, item: any) => sum + item.price, 0);
}
Interface vs Type
// Use interface for objects
interface User {
id: string;
name: string;
}
// Use type for unions, intersections
type Status = 'pending' | 'completed' | 'failed';
type UserWithStatus = User & { status: Status };
Optional Properties
// Good: Clear optional properties
interface Props {
title: string;
description?: string;
onClick?: () => void;
}
React
Component Structure
'use client'; // If needed
import { useState, useEffect } from 'react';
type Props = {
userId: string;
};
export default function UserComponent({ userId }: Props) {
// 1. Hooks
const [user, setUser] = useState<User | null>(null);
// 2. Effects
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
// 3. Handlers
const handleClick = () => {
// Handler logic
};
// 4. Render
if (!user) return <LoadingState />;
return (
<div>
<h1>{user.name}</h1>
</div>
);
}
Hooks
// Custom hooks: use prefix
export function useUserData(userId: string) {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
return user;
}
Props
// Good: Destructured props
function Component({ title, description }: Props) {
return <div>{title}</div>;
}
// Bad: Props object
function Component(props: Props) {
return <div>{props.title}</div>;
}
Imports
Import Order
// 1. React and Next.js
import React from 'react';
import { useState } from 'react';
import Link from 'next/link';
// 2. Third-party libraries
import { format } from 'date-fns';
// 3. Internal components
import Button from '@/components/Button';
import Modal from '@/components/Modal';
// 4. Internal hooks
import { useForm } from '@/hooks/useForm';
// 5. Internal utilities
import { formatCurrency } from '@/lib/utils';
// 6. Types
import type { User } from '@/types/user';
// 7. Styles
import './styles.css';
Import Aliases
// Use @/ alias for imports
import Component from '@/components/Component';
import { useHook } from '@/hooks/useHook';
import { utility } from '@/lib/utility';
Formatting
Indentation
// Use 2 spaces
function example() {
if (condition) {
return true;
}
}
Line Length
// Keep lines under 100 characters
// Break long lines
const longString =
'This is a very long string that needs to be broken ' +
'across multiple lines for readability';
Spacing
// Good: Consistent spacing
function example(a: number, b: number) {
if (a > b) {
return a;
}
return b;
}
// Bad: Inconsistent spacing
function example(a:number,b:number){
if(a>b){
return a;
}
return b;
}
Comments
When to Comment
// Good: Explain why, not what
// Calculate discount based on user tier
const discount = calculateDiscount(user.tier);
// Bad: Obvious comment
// Set discount to calculated discount
const discount = calculateDiscount(user.tier);
JSDoc Comments
/**
* Calculates the total price including tax
* @param price - Base price
* @param taxRate - Tax rate as decimal (e.g., 0.1 for 10%)
* @returns Total price with tax
*/
function calculateTotal(price: number, taxRate: number): number {
return price * (1 + taxRate);
}
Error Handling
Try-Catch
// Good: Specific error handling
try {
const data = await fetchData();
return data;
} catch (error) {
if (error instanceof NetworkError) {
// Handle network error
} else {
// Handle other errors
}
throw error;
}
Error Messages
// Good: Descriptive error messages
throw new Error('Failed to fetch user data: Network timeout');
// Bad: Vague error messages
throw new Error('Error');
Performance
Memoization
// Use memoization for expensive calculations
const expensiveValue = useMemo(() => {
return computeExpensiveValue(data);
}, [data]);
// Use callback memoization
const handleClick = useCallback(() => {
doSomething(id);
}, [id]);
Lazy Loading
// Lazy load heavy components
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
loading: () => <LoadingState />,
});
Testing
Test Structure
describe('Component', () => {
it('renders correctly', () => {
render(<Component />);
expect(screen.getByText('Hello')).toBeInTheDocument();
});
it('handles user interaction', () => {
render(<Component />);
fireEvent.click(screen.getByRole('button'));
expect(screen.getByText('Clicked')).toBeInTheDocument();
});
});
Git Commit Messages
Format
type(scope): subject
body
footer
Types
feat: New featurefix: Bug fixdocs: Documentationstyle: Formattingrefactor: Code refactoringtest: Testschore: Maintenance
Examples
feat(auth): add login functionality
Add user login with email and password validation.
Closes #123
ESLint Configuration
Rules
Follow the project's ESLint configuration:
- Use TypeScript strict mode
- No
anytypes - Prefer const over let
- No unused variables
Disabling Rules
// Only disable when necessary with explanation
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const data: any = fetchData();