reactpropsfrontendMahir4 mnt baca

Typing Props di React

Anotasi props komponen React: interface Props, children, dan default props.

Kenapa Typing Props Penting

Di React tanpa TypeScript, props adalah kotak hitam: komponen menerima object, dan kamu baru tahu ada yang kurang saat UI-nya rusak di browser. Dengan props yang di-type, kesalahan seperti lupa mengirim prop wajib atau salah tipe ketahuan saat kamu menulis JSX, lengkap dengan nama prop yang bermasalah. Untuk tim, interface props juga berfungsi sebagai dokumentasi hidup: cukup baca interface-nya untuk tahu cara memakai komponen tanpa membuka implementasinya.

Kapan Dipakai

Setiap komponen yang kamu tulis, tanpa kecuali. Pola standarnya: satu interface XxxProps per komponen, didefinisikan tepat di atas komponennya. Prop wajib tanpa tanda tanya, prop opsional dengan ?, nilai terbatas dengan literal union, dan handler dengan tipe fungsi eksplisit.

Contoh 1: Komponen UserCard yang Realistis

tsx
import type { ReactNode } from "react";

interface UserCardProps {
  id: string;
  nama: string;
  peran: "admin" | "kasir" | "pelanggan";
  avatarUrl?: string;
  onPilih: (id: string) => void;
  children?: ReactNode;
}

function UserCard({ id, nama, peran, avatarUrl, onPilih, children }: UserCardProps) {
  return (
    <div className="card" onClick={() => onPilih(id)}>
      {avatarUrl ? (
        <img src={avatarUrl} alt={nama} />
      ) : (
        <div className="avatar-fallback">{nama[0]}</div>
      )}
      <h3>{nama}</h3>
      <span className={`badge ${peran}`}>{peran}</span>
      {children}
    </div>
  );
}

Perhatikan polanya: prop wajib (id, nama, peran, onPilih) tanpa tanda tanya, prop opsional (avatarUrl, children) dengan ?, nilai terbatas (peran) dengan literal union sehingga typo seperti "admni" langsung ditolak, dan handler (onPilih) dengan tipe fungsi eksplisit agar pemanggil tahu argumen apa yang akan diterima.

Contoh 2: Error Compiler Nyata di JSX

tsx
// Salah nilai literal:
<UserCard id="u1" nama="Budi" peran="superadmin" onPilih={(id) => console.log(id)} />
// Error: Type '"superadmin"' is not assignable to type
// '"admin" | "kasir" | "pelanggan"'. (TS2322)

// Lupa prop wajib:
<UserCard id="u1" nama="Budi" peran="kasir" />
// Error: Property 'onPilih' is missing in type
// '{ id: string; nama: string; peran: "kasir"; }' but required
// in type 'UserCardProps'. (TS2741)

Dua error paling umum di JSX. TS2322 bilang nilainya salah, TS2741 bilang ada prop wajib yang kurang. Keduanya menunjuk nama prop persisnya, jadi perbaikannya langsung jelas tanpa menebak-nebak.

Contoh 3: Default Props yang Type-Safe

tsx
interface TombolProps {
  label: string;
  varian?: "primer" | "sekunder";
  onKlik: () => void;
}

function Tombol({ label, varian = "primer", onKlik }: TombolProps) {
  return (
    <button className={`btn ${varian}`} onClick={onKlik}>
      {label}
    </button>
  );
}

// <Tombol label="Simpan" onKlik={simpan} />            varian = "primer"
// <Tombol label="Hapus" varian="sekunder" onKlik={h} /> varian = "sekunder"

Destructuring dengan nilai default adalah cara modern menggantikan defaultProps (yang sudah deprecated untuk function component). TypeScript memahami bahwa di dalam komponen, varian bertipe "primer" | "sekunder" murni, bukan undefined lagi, karena default-nya selalu mengisi.

Catatan teknis: Jangan pakai React.FC di kode baru. Selain diam-diam menambah children opsional ke semua komponen, ia juga merusak inference pada komponen generic. Interface props eksplisit seperti di atas adalah rekomendasi komunitas modern dan dokumentasi resmi React.

Tantangan

Komponen Badge

Buat interface BadgeProps { teks: string; warna?: "merah" | "hijau" | "biru"; onTutup?: () => void } dan komponen Badge yang me-render span dengan class warna dan tombol tutup (×) hanya bila onTutup ada.

typescript
interface BadgeProps {
  teks: string;
  warna?: "merah" | "hijau" | "biru";
  onTutup?: () => void;
}

function Badge({ teks, warna = "biru", onTutup }: BadgeProps) {
  // render span + tombol tutup kondisional
}