Twenty emphasizes clean, readable, and maintainable code. This document outlines our code style conventions and best practices.
- 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; };
- 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';
- 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'; } };
- 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;
- 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; };
- 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';
- 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 });
- 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';
- 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; } };
- 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 } }