Interface Dasar
Mendefinisikan kontrak bentuk object dengan interface: cara paling idiomatis di TypeScript.
Analogi: Formulir Pendaftaran
Bayangin kamu panitia lomba. Setiap peserta ngisi formulir yang sama: nama, umur, nomor HP. Formulir itu "cetakannya", data tiap peserta adalah "isiannya". Kalau ada yang ngisi umur pakai tulisan "tujuh belas" atau lupa ngisi nama, panitia langsung protes.
interface di TypeScript itu formulirnya. Dia mendefinisikan bentuk (shape) sebuah object: properti apa saja yang wajib ada dan tipenya apa. Compiler jadi "panitia" yang ngecek setiap object sebelum program jalan.
Kenapa Interface Ada?
Di JavaScript murni, bentuk object cuma "kesepakatan lisan". Kamu bikin object user di satu file dengan properti nama, di file lain ngetiknya name karena lupa, dan bug-nya baru ketahuan pas aplikasi crash di tangan user.
Masalah yang diselesaikan interface:
- Anotasi object yang diulang-ulang. Tanpa interface, setiap fungsi yang menerima user harus nulis
{ nama: string; umur: number }berulang kali. Sekali bentuknya berubah, kamu harus ubah di semua tempat. - Typo properti yang lolos diam-diam. Salah ketik
emialbukannyaemailtidak akan ketahuan sampai runtime. - Dokumentasi bentuk data. Interface adalah dokumentasi yang bisa dieksekusi: bentuk data API, props komponen, dan config semuanya terdokumentasi dalam kode.
Contoh masalahnya dulu:
// Tanpa interface: anotasi diulang di mana-mana
function simpanUser(u: { nama: string; umur: number }) { /* ... */ }
function tampilkanUser(u: { nama: string; umur: number }) { /* ... */ }
// Besok tambah properti email -> ubah dua-duanya. Lelah.Versi rapi dengan interface:
interface Pengguna {
nama: string;
umur: number;
}
function simpanUser(u: Pengguna) { /* ... */ }
function tampilkanUser(u: Pengguna) { /* ... */ }
// Tambah email? Cukup ubah interface-nya sekali.Contoh Error Compiler yang Nyata
Compiler tidak main-main soal kontrak. Lihat:
interface Siswa {
nama: string;
umur: number;
}
const a: Siswa = { nama: "Budi", umur: 17 }; // OK
const b: Siswa = { nama: "Ani" };
// Error: Property 'umur' is missing in type '{ nama: string; }'
// but required in type 'Siswa'.
const c: Siswa = { nama: "Cici", umur: "tujuh belas" };
// Error: Type 'string' is not assignable to type 'number'.Pesan errornya selalu menunjuk properti yang bermasalah dan tipe yang diharapkan. Ini jauh lebih murah daripada debugging di runtime.
Properti Opsional dan Readonly
Tidak semua properti wajib. Tanda ? artinya boleh tidak ada, readonly artinya tidak boleh diubah setelah dibuat:
interface Produk {
readonly id: string;
nama: string;
diskon?: number; // boleh tidak ada
}
const p: Produk = { id: "P-1", nama: "Kopi" }; // OK, diskon absen
p.id = "P-2";
// Error: Cannot assign to 'id' because it is a read-only property.Kombinasi ini sangat umum untuk data dari API: id tidak boleh diubah siapa pun, diskon kadang tidak dikirim server.
Catatan teknis:
readonlyhanya dijaga saat compile time. Kalau object-nya datang dariJSON.parse, tidak ada yang mencegah kode nakal mengubahnya lewatany. Anggapreadonlysebagai rambu, bukan gembok.
Kesalahan Umum Pemula
1. Menyalin anotasi object ke mana-mana
SALAH:
function a(u: { nama: string; umur: number }) {}
function b(u: { nama: string; umur: number }) {}
function c(u: { nama: string; umur: number }) {}
// Tambah satu properti = ubah tiga tempatBENAR:
interface Pengguna { nama: string; umur: number; }
function a(u: Pengguna) {}
function b(u: Pengguna) {}
function c(u: Pengguna) {}
// Tambah properti = ubah satu tempat2. Lupa tanda ? lalu protes saat properti absen
SALAH:
interface Produk { nama: string; diskon: number; }
const p: Produk = { nama: "Kopi" };
// Error: Property 'diskon' is missing...
// Padahal diskon memang boleh tidak adaBENAR:
interface Produk { nama: string; diskon?: number; }
const p: Produk = { nama: "Kopi" }; // OK3. Pakai prefix I seperti di C#
SALAH:
interface ISiswa { nama: string; } // gaya C#, tidak idiomatis di TSBENAR:
interface Siswa { nama: string; } // PascalCase polos4. Mengira readonly melindungi saat runtime
SALAH (ekspektasi keliru):
interface Config { readonly apiKey: string; }
const cfg = JSON.parse('{"apiKey":"abc"}') as Config;
(cfg as any).apiKey = "diubah"; // lolos! readonly cuma compile-timeBENAR (pahami batasnya):
// readonly mencegah salah tulis di kode sendiri, bukan serangan.
// Untuk data sensitif, jangan taruh di client sama sekali.Kapan Dipakai di Project Nyata
Hampir di semua tempat: bentuk response API (interface UserResponse), props komponen React (interface ButtonProps), baris data di tabel, dan object konfigurasi. Aturan praktisnya: kalau sebuah bentuk object dipakai lebih dari sekali atau diekspor ke file lain, beri dia interface. Kalau cuma sekali pakai di satu fungsi kecil, anotasi inline masih boleh.
Tantangan
Kontrak data pengguna
Buat interface Pengguna dengan id: string (readonly), nama: string, email: string, dan umur?: number. Lalu buat dua object: satu valid, satu yang sengaja salah (umur diisi string). Amati error compilernya.
interface Pengguna {
// tulis di sini
}
const valid: Pengguna = { id: "U1", nama: "Budi", email: "[email protected]" };
const salah: Pengguna = { id: "U2", nama: "Ani", email: "[email protected]", umur: "tujuh belas" };