6.2 KiB
6.2 KiB
Code Style Guidelines
Core Code Style Principles
Twenty emphasizes clean, readable, and maintainable code. This document outlines our code style conventions and best practices.
Control Flow
Early Returns
- Use early returns to reduce nesting
- Handle edge cases first
// ✅ Correct const processUser = (user: User | null) => { if (!user) return null; if (!user.isActive) return null; return { id: user.id, name: user.name, }; }; // ❌ Incorrect const processUser = (user: User | null) => { if (user) { if (user.isActive) { return { id: user.id, name: user.name, }; } } return null; };
No Nested Ternaries
- Avoid nested ternary operators
- Use if statements or early returns
// ✅ Correct const getUserDisplay = (user: User) => { if (!user.name) return 'Anonymous'; if (!user.isActive) return 'Inactive User'; return user.name; }; // ❌ Incorrect const getUserDisplay = (user: User) => user.name ? user.isActive ? user.name : 'Inactive User' : 'Anonymous';
No Else-If Chains
- Use switch statements or lookup objects
- Keep conditions flat
// ✅ Correct const getStatusColor = (status: Status): string => { switch (status) { case 'success': return 'green'; case 'warning': return 'yellow'; case 'error': return 'red'; default: return 'gray'; } }; // Or using a lookup object const statusColors: Record<Status, string> = { success: 'green', warning: 'yellow', error: 'red', default: 'gray', }; // ❌ Incorrect const getStatusColor = (status: Status): string => { if (status === 'success') { return 'green'; } else if (status === 'warning') { return 'yellow'; } else if (status === 'error') { return 'red'; } else { return 'gray'; } };
Operators and Expressions
Optional Chaining Over &&
- Use optional chaining for null/undefined checks
- Clearer intent and better type safety
// ✅ Correct const userName = user?.name; const userAddress = user?.address?.street; // ❌ Incorrect const userName = user && user.name; const userAddress = user && user.address && user.address.street;
Function Design
Small Focused Functions
- Keep functions small and single-purpose
- Extract complex logic into helper functions
// ✅ Correct const validateUser = (user: User) => { if (!isValidName(user.name)) return false; if (!isValidEmail(user.email)) return false; if (!isValidAge(user.age)) return false; return true; }; const isValidName = (name: string) => { return name.length >= 2 && /^[a-zA-Z\s]*$/.test(name); }; const isValidEmail = (email: string) => { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); }; const isValidAge = (age: number) => { return age >= 18 && age <= 120; }; // ❌ Incorrect const validateUser = (user: User) => { if (user.name.length < 2 || !/^[a-zA-Z\s]*$/.test(user.name)) return false; if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(user.email)) return false; if (user.age < 18 || user.age > 120) return false; return true; };
Naming and Documentation
Clear Variable Names
- Use descriptive, intention-revealing names
- Avoid abbreviations unless common
// ✅ Correct const isUserActive = user.status === 'active'; const hasRequiredPermissions = user.permissions.includes('admin'); const userDisplayName = user.name || 'Anonymous'; // ❌ Incorrect const active = user.status === 'active'; const hasPerm = user.permissions.includes('admin'); const udn = user.name || 'Anonymous';
No Console.logs in Commits
- Remove all console.logs before committing
- Use proper logging/error tracking in production
// ❌ Incorrect - Don't commit these console.log('user:', user); console.log('debug:', someValue); // ✅ Correct - Use proper logging logger.info('User action completed', { userId: user.id }); logger.error('Operation failed', { error });
Minimal Comments
- Write self-documenting code
- Use comments only for complex business logic
// ✅ Correct // Calculate pro-rated amount based on billing cycle const calculateProRatedAmount = (amount: number, daysLeft: number, totalDays: number) => { return (amount * daysLeft) / totalDays; }; // ❌ Incorrect - Unnecessary comments // Get the user's name const getUserName = (user: User) => user.name; // Check if user is active const isUserActive = (user: User) => user.status === 'active';
Error Handling
Proper Error Handling
- Use try-catch blocks appropriately
- Provide meaningful error messages
// ✅ Correct const fetchUserData = async (userId: string) => { try { const response = await api.get(`/users/${userId}`); return response.data; } catch (error) { logger.error('Failed to fetch user data', { userId, error: error instanceof Error ? error.message : 'Unknown error', }); throw new UserFetchError('Failed to fetch user data'); } }; // ❌ Incorrect const fetchUserData = async (userId: string) => { try { const response = await api.get(`/users/${userId}`); return response.data; } catch (error) { console.log('error:', error); throw error; } };
Code Organization
Logical Grouping
- Group related code together
- Maintain consistent organization
// ✅ Correct class UserService { // Properties private readonly api: Api; private readonly logger: Logger; // Constructor constructor(api: Api, logger: Logger) { this.api = api; this.logger = logger; } // Public methods public async getUser(id: string): Promise<User> { // Implementation } public async updateUser(user: User): Promise<User> { // Implementation } // Private helpers private validateUser(user: User): boolean { // Implementation } }