TypeScript în React și Next
Props, children, state, evenimente, reducer tipat și PageProps.
Actualizat
Ce înseamnă să tipezi React
În React, TS verifică trei lucruri principale: props-urile pe care le primește o componentă, state-ul și evenimentele. Rezultatul: autocomplete pentru props, erori când uiți unul obligatoriu, refactorizări fără frică.
Props
type ButtonProps = {
variant?: 'primary' | 'secondary'
size?: 'sm' | 'md'
children: React.ReactNode
onClick?: () => void
}
export function Button({ variant = 'primary', size = 'md', children, onClick }: ButtonProps) {
return <button onClick={onClick}>{children}</button>
}Extinzi props-urile unui element nativ
În loc să enumeri type, disabled, aria-*... manual:
type Props = React.ComponentProps<'button'> & { variant?: 'primary' | 'ghost' }
export function Button({ variant = 'primary', className, ...props }: Props) {
return <button className={cn(variants[variant], className)} {...props} />
}Exact cum e scris shared/ui/button.tsx din proiect.
Tipuri pentru children — diferențe
| Tip | Acceptă | Când |
|---|---|---|
React.ReactNode |
orice se poate randa: JSX, string, număr, null, array |
implicit pentru children |
React.ReactElement |
doar un element JSX | când chiar ai nevoie de un element (rar) |
string |
doar text | label-uri simple |
State
const [count, setCount] = useState(0) // inferență: number
const [user, setUser] = useState<User | null>(null) // generic explicit când inițialul e null
const [status, setStatus] = useState<'idle' | 'loading'>('idle')Evenimente
function onChange(e: React.ChangeEvent<HTMLInputElement>) {
setQuery(e.target.value)
}
function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
const data = new FormData(e.currentTarget)
}Truc: scrie handler-ul inline (onChange={e => ...}) — TS deduce tipul; treci cu mouse-ul peste e și copiază-l.
Reducer cu discriminated union
type Action =
| { type: 'add'; text: string }
| { type: 'toggle'; id: number }
function reducer(state: Todo[], action: Action): Todo[] {
switch (action.type) {
case 'add': return [...state, { id: Date.now(), text: action.text, done: false }]
case 'toggle': return state.map(t => (t.id === action.id ? { ...t, done: !t.done } : t))
}
}dispatch({ type: 'add' }) fără text → eroare. Vezi Union types.
Specific Next.js
export default async function Page({ params }: PageProps<'/blog/[slug]'>) {
const { slug } = await params // tipat automat din structura folderelor
}
export default function Layout({ children }: LayoutProps<'/'>) { ... }PageProps și LayoutProps sunt generate de Next din rutele tale.
Pe scurt
- Props ca
type;ComponentProps<'button'>pentru a extinde elemente native. children: React.ReactNode;useState<T>când inițialul nu spune tot.- Evenimente:
ChangeEvent,FormEvent; reducer cu union de acțiuni.