JavaScript adalah bahasa yang bertipe dinamis: sebuah variable boleh menampung string sekarang lalu number lima baris kemudian, dan tidak ada yang protes. Kebebasan tersebut terasa menyenangkan pada skrip kecil, tetapi berubah menjadi sumber kejadian aneh ketika proyek tumbuh menjadi puluhan berkas dengan banyak kontributor. Kesalahan kecil seperti salah ketik nama properti tidak terdeteksi saat penulisan; kesalahan tersebut menunggu kode berjalan — kadang di komputer pembaca akhir. TypeScript hadir untuk menutup celah tersebut dengan menambahkan lapisan tipe di atas JavaScript, dan pada chapter ini kita akan melihat secara konkret kelas kesalahan apa saja yang berhasil ditangkap sebelum kode sempat berjalan.
Tiga Kesalahan Klasik pada JavaScript #
Sebelum membicarakan solusi, mari kita petakan dulu masalahnya. Tiga pola kesalahan berikut muncul berulang kali pada proyek JavaScript yang tumbuh besar:
| Pola kesalahan | Perlakuan JavaScript | Akibat yang terasa |
|---|---|---|
Salah ketik nama properti (pengguna.nmaa) | Tidak ada error; hasilnya undefined | undefined mengalir ke kode lain hingga menimbulkan kegagalan di tempat yang jauh |
Argumen bertipe berbeda (hitungTotal(5000, "3")) | Koersi tipe otomatis | Program tetap berjalan, tetapi hasilnya salah secara diam-diam |
| Field wajib tidak terisi saat membuat object | Tidak ada error | Data yang tidak lengkap tersimpan dan baru terasa saat dibaca |
Ketiganya berbahaya bukan karena membuat program berhenti, melainkan karena program tetap berjalan dengan hasil yang salah. Kesalahan yang langsung melempar exception mudah dilacak; kesalahan yang menghasilkan undefined atau "50003" bisa lolos dari pemeriksaan singkat dan baru ditemukan berhari-hari kemudian.
Kesalahan yang Baru Muncul Saat Kode Berjalan #
Mari kita turunkan teori di atas menjadi kode nyata. Berkas berikut memuat dua kesalahan dari tabel: argumen bertipe berbeda dan salah ketik nama properti:
const pengguna = { nama: "Budi" };
function hitungTotal(harga, jumlah) {
return harga + jumlah;
}
console.log(hitungTotal(5000, "3"));
try {
console.log(pengguna.nmaa.toUpperCase());
} catch (error) {
console.log(`${error.name}: ${error.message}`);
}Output yang Dihasilkan:
50003
TypeError: Cannot read properties of undefined (reading 'toUpperCase')Mari kita telaah baris-baris kode di atas:
- Baris 3-5 (
function hitungTotal(...)): function menerima dua parameter tanpa anotasi tipe apa pun, sehingga JavaScript menerima argumen dengan tipe bebas. - Baris 7 (
console.log(hitungTotal(5000, "3"))): operator+menemukan number dan string, lalu memilih menggabungkan keduanya sebagai string — hasilnya"50003", bukan15000. Tidak ada error yang dilempar; angka yang salah ini bisa tersimpan ke database atau dikirim sebagai respons API. - Baris 10 (
pengguna.nmaa.toUpperCase()): propertinmaatidak ada pada object, sehingga nilainyaundefined. Memanggil.toUpperCase()padaundefinedbaru gagal di titik ini — jauh dari lokasi kesalahan ketiknya. - Baris 11-13 (
catch (error)): error ditangkap agar program tidak berhenti, laluerror.namedanerror.messagedicetak tanpa stack trace agar keluaran mudah dibaca.
Perhatikan polanya: satu kesalahan menghasilkan nilai salah secara diam-diam, satu lagi baru gagal ketika nilai undefined itu dipakai. Keduanya lolos sepenuhnya pada saat penulisan kode.
TypeScript Memeriksa Sebelum Kode Berjalan #
TypeScript adalah superset dari JavaScript: seluruh kode JavaScript valid adalah kode TypeScript valid, ditambah anotasi tipe seperti nama: string. Anotasi tersebut dibaca oleh compiler tsc yang memeriksa kesesuaian antara deklarasi dan pemakaian — parameter yang dikirim, properti yang diakses, nilai yang dikembalikan — tanpa menjalankan kode. Mari kita ubah kesalahan ketik pertama menjadi versi bertipe:
interface Pengguna {
nama: string;
}
const pengguna: Pengguna = { nama: "Budi" };
console.log(pengguna.nmaa);Output yang Dihasilkan:
undefinedMenarik: Node.js tetap menjalankan berkas tersebut tanpa protes dan mencetak undefined, karena Node hanya menanggalkan anotasi tipe tanpa memeriksanya. Pemeriksaan terjadi di tempat lain — pada compiler. Jalankan tsc dengan opsi --noEmit (periksa saja, jangan hasilkan berkas output):
npx --yes [email protected] --noEmit salah-ketik.ts
echo kode keluar: $?Output yang Dihasilkan:
salah-ketik.ts(7,22): error TS2339: Property 'nmaa' does not exist on type 'Pengguna'.
kode keluar: 1Compiler menunjuk lokasi persisnya: berkas salah-ketik.ts, baris 7, kolom 22, disertai penjelasan bahwa properti nmaa tidak ada pada tipe Pengguna. Nilai kode keluar: 1 menandakan pemeriksaan gagal — nilai inilah yang nanti dimanfaatkan pipeline CI untuk menahan kode bermasalah agar tidak turun ke produksi.
Pola kedua — field wajib yang tertukar namanya — juga tertangkap dengan cara yang sama:
interface Pengguna {
nama: string;
email: string;
}
function tampilkan(pengguna: Pengguna): string {
return `${pengguna.nama} <${pengguna.email}>`;
}
const budi = { nama: "Budi", emal: "[email protected]" };
console.log(tampilkan(budi));Output yang Dihasilkan:
Budi <undefined>npx --yes [email protected] --noEmit salah-salin.ts
echo kode keluar: $?Output yang Dihasilkan:
salah-salin.ts(12,23): error TS2741: Property 'email' is missing in type '{ nama: string; emal: string; }' but required in type 'Pengguna'.
kode keluar: 1Saat dijalankan dengan Node.js, template literal mencetak Budi <undefined> — data email hilang tanpa jejak. Compiler memberikan cerita yang jauh lebih informatif: properti email wajib ada, tetapi object yang dikirim hanya memiliki emal. Pesan seperti ini menghemat waktu penelusuran karena compiler menuliskan bentuk object yang ia terima versus bentuk yang ia harapkan.
Kelebihan dan Kekurangan #
TypeScript bukan obat untuk segala masalah; keputusan memakainya sebaiknya didasarkan pada timbangan yang jujur:
| Aspek | Penilaian |
|---|---|
| Kesalahan tertangani lebih awal | Kesalahan tipe, properti, dan field hilang terdeteksi sebelum kode berjalan |
| Bantuan editor | Editor memahami bentuk data sehingga autocomplete dan navigasi kode menjadi akurat |
| Dokumentasi hidup | Anotasi tipe selalu mutakhir karena ikut diperiksa compiler, tidak seperti komentar yang mudah usang |
| Biaya: langkah pemeriksaan | Proyek perlu menjalankan tsc pada alur kerja — sebagai perintah terpisah atau tahapan CI |
| Biaya: notasi ekstra | Anotasi menambah baris kode dan perlu dipelajari, terasa pada berkas kecil |
| Biaya: pembaruan | Ekosistem bergerak cepat; sesekali ada pola lama yang perlu disesuaikan dengan versi baru |
Untuk skrip satu berkas yang sekali pakai, JavaScript murni tetap masuk akal. Untuk proyek yang hidup berbulan-bulan dan disentuh banyak orang, pemeriksaan tipe umumnya membayar kembali biayanya. Panduan resmi TypeScript Handbook merupakan titik mulai yang baik untuk menjelajahi dokumentasinya, sementara dukungan TypeScript pada Node.js dijelaskan pada halaman resmi Node.js TypeScript .
Kita telah melihat alasan memakai TypeScript lewat perbandingan kejadian nyata: kesalahan yang semula baru terlihat saat berjalan kini tertangkap compiler dengan lokasi dan penjelasan yang presisi. Langkah berikutnya adalah menyiapkan proyek yang menerapkan pengetahuan ini secara tertata — lewat package.json, tsconfig.json, dan struktur folder yang rapi pada chapter Setup Proyek TypeScript.