TypeScript React Patterns
Comprehensive TypeScript patterns for React applications. Contains 35+ rules across 7 categories for building type-safe, maintainable React code.
When to Apply
Reference these guidelines when:
Typing React component props Creating custom hooks with TypeScript Handling events with proper types Building generic, reusable components Fixing TypeScript errors in React code Rule Categories by Priority Priority Category Impact Prefix 1 Component Typing CRITICAL comp- 2 Hook Typing CRITICAL hook- 3 Event Handling HIGH event- 4 Ref Typing HIGH ref- 5 Generic Components MEDIUM generic- 6 Context & State MEDIUM ctx- 7 Utility Types LOW util- Quick Reference 1. Component Typing (CRITICAL) comp-props-interface - Use interface for props, type for unions comp-children-types - Correct children typing patterns comp-default-props - Default props with TypeScript comp-forward-ref - Typing forwardRef components comp-compound - Compound component patterns comp-polymorphic - "as" prop typing 2. Hook Typing (CRITICAL) hook-usestate - useState with proper types hook-useref - useRef for DOM and mutable values hook-useeffect - useEffect cleanup typing hook-usereducer - useReducer with discriminated unions hook-custom-return - Custom hook return types hook-generic - Generic custom hooks 3. Event Handling (HIGH) event-handler-types - Event handler type patterns event-synthetic - SyntheticEvent types event-form - Form event handling event-keyboard - Keyboard event types event-mouse - Mouse event types event-custom - Custom event types 4. Ref Typing (HIGH) ref-dom-elements - Refs for DOM elements ref-mutable - Mutable ref pattern ref-callback - Callback ref typing ref-forward - Forwarding refs ref-imperative-handle - useImperativeHandle typing 5. Generic Components (MEDIUM) generic-list - Generic list components generic-form - Generic form components generic-select - Generic select/dropdown generic-table - Generic table components generic-constraints - Generic constraints 6. Context & State (MEDIUM) ctx-create - Creating typed context ctx-provider - Provider typing patterns ctx-consumer - useContext with proper types ctx-reducer - Context with reducer ctx-default-value - Handling default values 7. Utility Types (LOW) util-react-types - Built-in React types util-component-props - ComponentProps utility util-pick-omit - Pick and Omit for props util-discriminated-unions - State machines util-assertion-functions - Type assertions Essential Patterns Component Props // Use interface for props (extendable) interface ButtonProps { variant: 'primary' | 'secondary' | 'danger' size?: 'sm' | 'md' | 'lg' isLoading?: boolean children: React.ReactNode onClick?: () => void }
// Use type for unions type ButtonVariant = 'primary' | 'secondary' | 'danger'
function Button({ variant, size = 'md', isLoading = false, children, onClick, }: ButtonProps) { return ( ) }
Children Typing // ReactNode - most flexible (string, number, element, array, null) interface CardProps { children: React.ReactNode }
// ReactElement - only JSX elements interface WrapperProps { children: React.ReactElement }
// Render prop pattern
interface DataFetcherProps
// Specific element type
interface TabsProps {
children: React.ReactElement
Event Handlers
// Form events
function Form() {
const handleSubmit = (e: React.FormEvent
const handleChange = (e: React.ChangeEvent
const handleSelect = (e: React.ChangeEvent
return (
) }Refs
// DOM element ref
function Input() {
const inputRef = useRef
const focus = () => { inputRef.current?.focus() }
return }
// Mutable ref (no null, stores values)
function Timer() {
const intervalRef = useRef
useEffect(() => { intervalRef.current = window.setInterval(() => { // tick }, 1000)
return () => {
clearInterval(intervalRef.current)
}
}, []) }
Generic Components
// Generic list component
interface ListProps
function List
{items.map((item, index) => (
)
}
// Usage - T is inferred
Context
interface AuthContextType {
user: User | null
login: (credentials: Credentials) => Promise
const AuthContext = createContext
export function useAuth() { const context = useContext(AuthContext) if (!context) { throw new Error('useAuth must be used within AuthProvider') } return context }
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState
const login = async (credentials: Credentials) => { // implementation }
const logout = () => { setUser(null) }
return (
How to Use
Read individual rule files for detailed explanations and code examples:
rules/comp-props-interface.md rules/hook-usestate.md rules/event-handler-types.md
Each rule file contains:
Brief explanation of why it matters Incorrect code example with explanation Correct code example with explanation Additional context and edge cases