Rules and best practices for working with React React + TypeScript Coding Standards You MUST always use functional components with TypeScript. You MUST define prop types using interface or type instead of relying on PropTypes. You MUST always type component props explicitly, even if they are empty (e.g., FC<{}> or React.FC<{ propName: string }>). You SHOULD NEVER use the any type. Use more specific types like unknown, string, or custom types/interfaces. You MUST type all state variables using useState (e.g., const [count, setCount] = useState<number>(0);). You MUST always type event handlers explicitly (e.g., (event: React.ChangeEvent<HTMLInputElement>) => void). JSX + TypeScript Best Practices You MUST always wrap multi-line JSX expressions in parentheses for better readability. You MUST use self-closing tags for elements without children (e.g., <img>, <input />). You SHOULD NEVER inline complex logic directly in JSX. Extract it into helper functions or variables for clarity. You MUST always provide a key prop when rendering lists of elements to ensure proper reconciliation by React. You SHOULD ALWAYS type refs using React.RefObject<T> or React.MutableRefObject<T>. Component Design Guidelines You MUST follow the Single Responsibility Principle (SRP) when designing components. Each component should do one thing well. You SHOULD NEVER create components with more than 200 lines of code . Break them into smaller, reusable components if necessary. You MUST always prefer composition over inheritance when creating reusable components. You SHOULD NEVER pass more than 5 props to a single component. Use objects or context if more data needs to be passed. For reusable components, you MUST use generic types where applicable (e.g., <T> for lists or forms). State Management with TypeScript You MUST manage local component state using useState or useReducer, and you MUST type the state explicitly. Example: const [state, setState] = useState<{ count: number }>({ count: 0 }); For global state, you SHOULD use a dedicated state management library (e.g., Redux, Zustand) or React Context API when appropriate, ensuring all actions and reducers are typed. You SHOULD NEVER store derived data in the state. Instead, compute it dynamically from existing state or props. You MUST always memoize expensive calculations using useMemo and functions using useCallback, ensuring proper typing for both. Example: const memoizedValue = useMemo<number>(() => computeExpensiveValue(a, b), [a, b]); You SHOULD NEVER pass anonymous functions as props unless memoization is unnecessary. You MUST use React.memo for functional components that do not need to re-render frequently. For large lists, you SHOULD ALWAYS use virtualization libraries like react-window or react-virtualized. Styling Guidelines You SHOULD prefer CSS-in-JS libraries (e.g., styled-components, Emotion) or utility-first CSS frameworks like TailwindCSS for styling components. When using styled-components or Emotion, you MUST type props explicitly in styled components:
const StyledButton = styled.button<{ isActive: boolean }>` background-color: ${(props) => (props.isActive ? 'blue' : 'gray')}; `;
You MUST scope styles to components to avoid global CSS conflicts. You SHOULD NEVER hardcode styles directly in JSX unless they are dynamic and cannot be handled via CSS. Testing Guidelines You MUST write unit tests for all critical components using the specified testing framework (e.g., React Testing Library). Tests SHOULD focus on user behavior and component output rather than implementation details. You SHOULD mock external dependencies in tests to isolate component behavior. For complex interactions, you MUST write integration tests that span multiple components. Error Handling You MUST handle errors gracefully using error boundaries (React.ErrorBoundary) where applicable. Error boundaries SHOULD be typed explicitly:
class ErrorBoundary extends React.Component<
{ children: React.ReactNode },
{ hasError: boolean }
> {
constructor(props: { children: React.ReactNode }) {
super(props);
this.state = { hasError: false };
}
// Implementation here
}
Accessibility Rules You MUST ensure all interactive elements have accessible labels (aria-label, aria-labelledby, etc.). The codebase MUST adhere to the linting rules defined in .eslintrc. Fix all linting issues before committing code. Use ESLint plugins like eslint-plugin-react and eslint-plugin-react-hooks. Include TypeScript-specific rules via @typescript-eslint. Prettier SHOULD be used as the default formatter for consistent styling across files.