Prototipe menu kantin Budi direncanakan berumur dua minggu: satu berkas JavaScript, tiga function, selesai. Delapan bulan kemudian prototipe itu masih hidup — kini 14 modul, dipakai tiga outlet, dan disunting empat orang. Minggu lalu pelanggan di satu outlet menerima struk dengan harga Rp0: satu modul membaca properti totalHarga, sementara modul lain menulis total. JavaScript tidak memberi peringatan apa pun pada penulisan yang salah seperti itu; program terus berjalan membawa undefined, dan gejala baru terlihat jauh dari tempat kesalahannya.

Tipe statis menata ulang situasi ini dengan satu aturan: bentuk data dinyatakan sekali, lalu diperiksa sebelum program dijalankan. Pertanyaannya bukan “apakah TypeScript bagus”, melainkan kapan biaya menambah tipe menjadi lebih kecil daripada biaya bug bentuk data. Chapter ini menimbang momen itu lewat sinyal yang bisa kita amati pada proyek sendiri — bukan lewat tren.

Sinyal yang Menandakan Proyek Butuh Tipe #

Empat sinyal paling sering muncul sebelum sebuah tim akhirnya memutuskan menambah tipe:

  • Kesalahan bentuk data berulang — program berjalan dengan undefined di tempat yang tidak terduga, dan setiap kali penyebabnya sama: properti salah nama atau nilai salah jenis.
  • Refactoring terasa berisiko — mengganti nama satu properti seharusnya sederhana, tetapi tidak ada yang memberi tahu berapa banyak berkas lain yang membaca nama lama; perubahan pun ditunda.
  • Kontrak data hanya ada di kepala — bentuk parameter sebuah function diketahui dari kebiasaan, bukan dari deklarasi, sehingga setiap pemanggil menebak sendiri.
  • Penulis kode bertambah — orang kedua yang menulis di basis kode yang sama tidak lagi berbagi konteks dengan orang pertama; tipe menjadi sarana komunikasi yang selalu tersedia.

Mekanismenya sederhana: TypeScript membandingkan setiap penugasan nilai dengan bentuk data yang dideklarasikan, lalu melaporkan semua ketidaksesuaian sebelum program berjalan. Laporan itu datang lengkap untuk seluruh proyek dalam sekali pemeriksaan — bukan satu per satu saat bug muncul di produksi.

Ukuran Tim Menggeser Ambang Keputusan #

Sinyal yang sama tidak punya bobot sama di setiap tim. Pada proyek satu orang, disiplin pribadi ditambah uji otomatis sering cukup: penulisnya mengingat bentuk datanya sendiri. Pada tim dua sampai lima orang, kontrak antar penulis mulai penting — dua orang bisa saja menulis properti berbeda untuk maksud yang sama. Pada tim yang besar atau terbagi lintas sub-tim, tipe menjadi bahasa bersama: keuntungan deklarasi eksplisit dikalikan jumlah orang yang membacanya.

Ambang keputusan juga bergeser dengan umur kode. Skrip CLI tiga puluh baris yang jarang disunting tidak menanggung banyak risiko bentuk data. Modul yang dipanggil dari sepuluh tempat dan disunting setiap bulan menanggung banyak. Aturan praktisnya: makin banyak tangan dan makin panjang umur kode, makin besar nilai tipe.

Prototipe vs Produksi #

Perbedaan prototipe dan produksi bukan soal kualitas kode, melainkan soal dua biaya yang berlawanan arah. Saat memprototipekan, bentuk data masih bergerak: hari ini pesanan punya total, besok menjadi daftar item. Anotasi tipe yang ditulis hari ini ikut dirombak besok, sehingga biayanya terasa nyata sementara manfaatnya belum. Saat produksi, arahnya berbalik: bentuk data sudah stabil, tetapi jumlah pemakai dan penulis bertambah, sehingga biaya satu bug bentuk data melonjak — seperti struk Rp0 milik Budi.

Dari sini lahir kaidah yang sering dipakai tim: kode yang direncanakan hidup dua minggu tetapi masih disunting delapan bulan kemudian adalah proyek produksi yang menyamar. Begitu pola itu terlihat, jalur adopsi bertahap dimulai — biasanya dari modul data inti yang paling banyak dibaca, bukan dari seluruh proyek sekaligus.

Menakar Sinyal dengan Checklist #

Supaya penilaian ini tidak berhenti sebagai perasaan, kita bisa menakarnya. Aturannya: empat sinyal diubah menjadi pemeriksaan yang bisa dijawab angka — ukuran tim, jumlah modul, frekuensi perubahan skema data, dan apakah modul dipakai tim lain. Mekanismenya: setiap sinyal yang aktif menambah skor satu, lalu skor menentukan saran — dua atau lebih berarti adopsi layak dipertimbangkan sekarang, satu berarti siapkan jalur bertahap, nol berarti JavaScript murni masih nyaman.

// sinyal-proyek.js — menimbang kapan proyek JavaScript mulai butuh tipe statis.
// Jalankan di terminal: node sinyal-proyek.js

function kumpulkanSinyal(proyek) {
  const sinyal = [];
  if (proyek.anggotaTim >= 3) {
    sinyal.push("tim lebih dari dua orang");
  }
  if (proyek.jumlahModul >= 10) {
    sinyal.push("modul mulai banyak (>= 10)");
  }
  if (proyek.perubahanSkemaPerBulan >= 2) {
    sinyal.push("skema data sering berubah");
  }
  if (proyek.dipakaiTimLain) {
    sinyal.push("dipakai tim lain");
  }
  return sinyal;
}

function rekomendasi(jumlahSinyal) {
  if (jumlahSinyal >= 2) {
    return "adopsi TypeScript layak dipertimbangkan sekarang";
  }
  if (jumlahSinyal === 1) {
    return "siapkan jalur adopsi: mulai dari modul data inti";
  }
  return "JavaScript murni masih nyaman; jaga konsistensi skema data";
}

const proyek = [
  {
    nama: "prototipe-menu",
    anggotaTim: 1,
    jumlahModul: 4,
    perubahanSkemaPerBulan: 1,
    dipakaiTimLain: false,
  },
  {
    nama: "kasir-multioutlet",
    anggotaTim: 5,
    jumlahModul: 14,
    perubahanSkemaPerBulan: 3,
    dipakaiTimLain: true,
  },
];

for (const p of proyek) {
  const sinyal = kumpulkanSinyal(p);
  console.log(`[${p.nama}] sinyal aktif: ${sinyal.length}`);
  for (const s of sinyal) {
    console.log(`  - ${s}`);
  }
  console.log(`  -> ${rekomendasi(sinyal.length)}`);
}

Output yang Dihasilkan:

text
[prototipe-menu] sinyal aktif: 0
  -> JavaScript murni masih nyaman; jaga konsistensi skema data
[kasir-multioutlet] sinyal aktif: 4
  - tim lebih dari dua orang
  - modul mulai banyak (>= 10)
  - skema data sering berubah
  - dipakai tim lain
  -> adopsi TypeScript layak dipertimbangkan sekarang

Mari kita telaah bagian-bagian pentingnya:

  1. Baris 4–19 (function kumpulkanSinyal(proyek) { ... }): setiap sinyal kualitatif diterjemahkan menjadi pemeriksaan terukur — jumlah anggota, jumlah modul, frekuensi perubahan skema, dan tanda boolean dipakaiTimLain. Function ini hanya mengukur; ia tidak memutuskan apa pun.
  2. Baris 21–29 (function rekomendasi(jumlahSinyal) { ... }): keputusan dipisah dari pengukuran. Ambang >= 2 berdiri sendiri, sehingga mengubah kebijakan (misalnya menjadi >= 3) cukup menyunting satu function.
  3. Baris 31–46 (const proyek = [ ... ]): dua profil nyata dijadikan data — prototipe Budi yang satu orang dengan empat modul, dan kasir multi-outlet milik tim Siti yang memenuhi keempat sinyal.
  4. Baris 48–55 (for (const p of proyek) { ... }): laporan dicetak per proyek: skor, daftar sinyal aktif, lalu saran. Keluaran memperlihatkan dua ujung spektrum: nol sinyal berarti tetap nyaman, empat sinyal berarti waktunya sekarang.

Checklist seperti ini juga membuat diskusi adopsi berhenti menjadi perdebatan selera. Bila satu hari sinyal prototipe Budi bertambah — tim bertiga, modul dua belas — kita menjalankan ulang berkas yang sama dan membaca keputusannya, bukan menebaknya.

Untuk menghubungkan chapter ini dengan materi teknis di depan, kontrak yang selama ini kita tulis sebagai kebiasaan bisa dinyatakan eksplisit. Bentuk data pesanan Budi, misalnya, ditulis dalam TypeScript seperti ini:

ts Ilustrasi: kontrak pesanan sebagai tipe
type Pesanan = {
  nomor: string;
  totalHarga: number;
  selesai: boolean;
};

function tandaiSelesai(pesanan: Pesanan): Pesanan {
  return { ...pesanan, selesai: true };
}

Blok TypeScript di chapter ini dan seterusnya tidak dijalankan langsung di terminal — kode TypeScript butuh langkah kompilasi menjadi JavaScript sebelum berjalan, dan proses itu dibahas penuh di chapter Transpilation Overview. Yang penting di sini adalah bentuknya: satu deklarasi Pesanan menggantikan semua tebakan tentang properti yang dimiliki pesanan. Perbedaan sintaks, inferensi tipe, dan biaya adopsinya dibedah chapter berikutnya.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

sinyal-proyek.js

Unduh berkas
javascript
// sinyal-proyek.js — menimbang kapan proyek JavaScript mulai butuh tipe statis.
// Jalankan di terminal: node sinyal-proyek.js

function kumpulkanSinyal(proyek) {
  const sinyal = [];
  if (proyek.anggotaTim >= 3) {
    sinyal.push("tim lebih dari dua orang");
  }
  if (proyek.jumlahModul >= 10) {
    sinyal.push("modul mulai banyak (>= 10)");
  }
  if (proyek.perubahanSkemaPerBulan >= 2) {
    sinyal.push("skema data sering berubah");
  }
  if (proyek.dipakaiTimLain) {
    sinyal.push("dipakai tim lain");
  }
  return sinyal;
}

function rekomendasi(jumlahSinyal) {
  if (jumlahSinyal >= 2) {
    return "adopsi TypeScript layak dipertimbangkan sekarang";
  }
  if (jumlahSinyal === 1) {
    return "siapkan jalur adopsi: mulai dari modul data inti";
  }
  return "JavaScript murni masih nyaman; jaga konsistensi skema data";
}

const proyek = [
  {
    nama: "prototipe-menu",
    anggotaTim: 1,
    jumlahModul: 4,
    perubahanSkemaPerBulan: 1,
    dipakaiTimLain: false,
  },
  {
    nama: "kasir-multioutlet",
    anggotaTim: 5,
    jumlahModul: 14,
    perubahanSkemaPerBulan: 3,
    dipakaiTimLain: true,
  },
];

for (const p of proyek) {
  const sinyal = kumpulkanSinyal(p);
  console.log(`[${p.nama}] sinyal aktif: ${sinyal.length}`);
  for (const s of sinyal) {
    console.log(`  - ${s}`);
  }
  console.log(`  -> ${rekomendasi(sinyal.length)}`);
}