webroad.online
  1. 1Web
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Unelte
  8. 8React
  9. 9State management
  10. 10Next.js
  11. 11Formulare
  12. 12Date și backend
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Animații
  16. 16Testare
  17. 17Arhitectură
TypeScript · Lecția 6 din 6

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.

Surse oficiale

Exerciții

Ți-a fost utilă pagina?

Un click — fără cont.