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 kesalahanPerlakuan JavaScriptAkibat yang terasa
Salah ketik nama properti (pengguna.nmaa)Tidak ada error; hasilnya undefinedundefined mengalir ke kode lain hingga menimbulkan kegagalan di tempat yang jauh
Argumen bertipe berbeda (hitungTotal(5000, "3"))Koersi tipe otomatisProgram tetap berjalan, tetapi hasilnya salah secara diam-diam
Field wajib tidak terisi saat membuat objectTidak ada errorData 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:

js
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:

text
50003
TypeError: Cannot read properties of undefined (reading 'toUpperCase')

Mari kita telaah baris-baris kode di atas:

  1. Baris 3-5 (function hitungTotal(...)): function menerima dua parameter tanpa anotasi tipe apa pun, sehingga JavaScript menerima argumen dengan tipe bebas.
  2. Baris 7 (console.log(hitungTotal(5000, "3"))): operator + menemukan number dan string, lalu memilih menggabungkan keduanya sebagai string — hasilnya "50003", bukan 15000. Tidak ada error yang dilempar; angka yang salah ini bisa tersimpan ke database atau dikirim sebagai respons API.
  3. Baris 10 (pengguna.nmaa.toUpperCase()): properti nmaa tidak ada pada object, sehingga nilainya undefined. Memanggil .toUpperCase() pada undefined baru gagal di titik ini — jauh dari lokasi kesalahan ketiknya.
  4. Baris 11-13 (catch (error)): error ditangkap agar program tidak berhenti, lalu error.name dan error.message dicetak 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:

ts
interface Pengguna {
  nama: string;
}

const pengguna: Pengguna = { nama: "Budi" };

console.log(pengguna.nmaa);

Output yang Dihasilkan:

text
undefined

Menarik: 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):

bash
npx --yes [email protected] --noEmit salah-ketik.ts
echo kode keluar: $?

Output yang Dihasilkan:

text
salah-ketik.ts(7,22): error TS2339: Property 'nmaa' does not exist on type 'Pengguna'.
kode keluar: 1

Compiler 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:

ts
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:

text
Budi <undefined>
bash
npx --yes [email protected] --noEmit salah-salin.ts
echo kode keluar: $?

Output yang Dihasilkan:

text
salah-salin.ts(12,23): error TS2741: Property 'email' is missing in type '{ nama: string; emal: string; }' but required in type 'Pengguna'.
kode keluar: 1

Saat 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:

AspekPenilaian
Kesalahan tertangani lebih awalKesalahan tipe, properti, dan field hilang terdeteksi sebelum kode berjalan
Bantuan editorEditor memahami bentuk data sehingga autocomplete dan navigasi kode menjadi akurat
Dokumentasi hidupAnotasi tipe selalu mutakhir karena ikut diperiksa compiler, tidak seperti komentar yang mudah usang
Biaya: langkah pemeriksaanProyek perlu menjalankan tsc pada alur kerja — sebagai perintah terpisah atau tahapan CI
Biaya: notasi ekstraAnotasi menambah baris kode dan perlu dipelajari, terasa pada berkas kecil
Biaya: pembaruanEkosistem 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.