Siti membuat laporanTotal(pesanan) untuk dashboard gudang. Satu hari formulir web mengirim field total dalam bentuk string — "150000", hasil langsung dari elemen <input> — dan pemanggilan total + ongkir pun menjawab "15000050000" tanpa galat apa pun. JavaScript menambahkan teks, bukan angka, dan program melanjutkan berjalan dengan laporan yang salah. Kesalahan itu baru ketahuan ketika kepal gudang bertanya kenapa totalnya berangka sebelas digit.
Persoalan itu bukan soal kelalaian; itu sifat bahasa bertipe dinamis. TypeScript memindahkan momen penemuan: nilai yang salah jenis dilaporkan sebelum program berjalan, bukan sesudah program memakainya. Chapter ini membandingkan keduanya — apa yang berubah pada sintaks, apa yang dikerjakan compiler, dan apa biaya yang harus dibayar tim yang mengadopsinya.
Superset: JavaScript, Ditambah Lapisan Tipe #
TypeScript adalah bahasa pemrograman yang dikembangkan Microsoft dan dirilis pada 2012 sebagai proyek open source. Desainnya dinyatakan lewat satu istilah: superset dari JavaScript. Seluruh sintaks JavaScript yang sudah kita pelajari tetap sah ditulis dalam TypeScript; bahasa ini hanya menambah lapisan sintaks tipe di atasnya. Berkas TypeScript memakai ekstensi .ts, dan kode TypeScript dikompilasi menjadi JavaScript — runtime, baik browser maupun Node.js, hanya pernah menjalankan hasil kompilasi itu.
Konsekuensi praktisnya menenangkan bagi pemilik kode lama: memindahkan laporan.js menjadi laporan.ts tidak mengubah perilaku program. Nilai, function, dan pola yang sudah ada tetap bekerja. Tipe kemudian ditambahkan bertahap, dimulai dari bagian yang paling sering menjadi sumber salah paham — biasanya bentuk data yang berpindah antar modul.
Anotasi Tipe Dasar #
Anotasi tipe menyatakan jenis nilai yang boleh menempati sebuah nama. Bentuknya titik dua diikuti nama tipe, ditulis pada variabel, parameter, dan nilai kembalian function:
const nama: string = "Budi";
let stok: number = 12;
let catatan: string | null = null;
function sapa(namaPengguna: string): string {
return "Halo, " + namaPengguna;
}Tiga bentuk penting terlihat di sini. Pertama, : string dan : number membatasi jenis nilai — penugasan stok = "dua belas" akan dilaporkan. Kedua, string | null adalah union: variabel catatan boleh berisi string atau null, dan penggunaannya tanpa pemeriksaan dilaporkan juga. Ketiga, anotasi pada parameter namaPengguna: string dan nilai kembalian : string membentuk kontrak function yang dapat diperiksa di setiap pemanggilan.
Sebagaimana disebut di chapter sebelumnya: blok .ts di chapter ini adalah ilustrasi dan tidak dijalankan di terminal. Kode TypeScript butuh langkah kompilasi sebelum berjalan; proses itu dibahas di chapter Transpilation Overview.
Inferensi: Tipe yang Ditebak Otomatis #
Anotasi bukan berarti setiap baris harus diberi label. Compiler menelusuri nilai awal dan alur data, lalu menyimpulkan tipenya sendiri — kemampuan ini disebut type inference:
const diskon = 0.1; // ditebak: number
const judul = "Kopi Gayo"; // ditebak: string
function totalHarga(harga: number, jumlah: number) {
return harga * jumlah; // ditebak: number, tanpa anotasi kembalian
}diskon diinisialisasi dengan angka, sehingga TypeScript menyimpulkan number; penugasan string kepadanya tetap dilaporkan walau tidak ada satu anotasi pun yang ditulis. Inferensi inilah yang menjaga kode tetap ringkas: penulisan TypeScript nyata lebih banyak berisi anotasi di batas-batas program — parameter function publik, bentuk data yang berpindah modul — dan hampir tanpa anotasi di bagian dalam.
Kaidah yang bisa kita pegang: anotasi ditempatkan di tempat informasi yang tidak terbaca dari kode sekitarnya. Bentuk parameter adalah informasi yang tidak terbaca dari pemanggil; nilai awal 0.1 sudah mengatakan sendiri tipenya.
Pemeriksaan Saat Kompilasi, Bukan Saat Berjalan #
Perbedaan terpenting kedua bahasa ini bukan pada sintaks, melainkan pada kapan kesalahan ditemukan. JavaScript menerima nilai apa pun sampai operasi yang gagal benar-benar dieksekusi. Karena itu proyek JavaScript murni menulis pemeriksaan bentuk secara manual — dan justru di sanalah kita bisa melihat apa yang compiler TypeScript kerjakan secara gratis:
// validasi-manual.js — pemeriksaan bentuk data yang di TypeScript dilakukan
// compiler, di JavaScript murni kita tulis sendiri saat runtime.
// Jalankan di terminal: node validasi-manual.js
function terimaPengguna(data) {
const galat = [];
if (typeof data.nama !== "string" || data.nama.length === 0) {
galat.push("nama harus string tidak kosong");
}
if (typeof data.email !== "string" || !data.email.includes("@")) {
galat.push("email tanpa tanda @");
}
if (typeof data.umur !== "number") {
galat.push(`umur harus number, diterima ${typeof data.umur}`);
}
if (galat.length > 0) {
throw new Error(galat.join("; "));
}
return `Pengguna valid diterima: ${data.nama}`;
}
console.log(terimaPengguna({ nama: "Budi", email: "[email protected]", umur: 25 }));
try {
terimaPengguna({ nama: "Siti", email: "[email protected]", umur: "dua puluh" });
} catch (error) {
console.log("Ditolak saat runtime:", error.message);
}
try {
terimaPengguna({ nama: "Rina", email: "rina.example.com", umur: 19 });
} catch (error) {
console.log("Ditolak saat runtime:", error.message);
}Output yang Dihasilkan:
Pengguna valid diterima: Budi
Ditolak saat runtime: umur harus number, diterima string
Ditolak saat runtime: email tanpa tanda @Mari kita telaah bagian-bagian pentingnya:
- Baris 5–20 (
function terimaPengguna(data) { ... }): setiap aturan bentuk data ditulis sebagai pemeriksaantypeofyang mengumpulkan pesan ke dalam arraygalat. Pemeriksaan baru bekerja jika pemanggil mengingat memanggilnya — penjagaan ini ada karena kesepakatan, bukan karena bahasa. - Baris 13–15 (
if (typeof data.umur !== "number") { ... }): kesalahan Siti —"dua puluh"sebagai umur — tertangkap di sini, tetapi hanya karena function ini dipanggil dan program berjalan sampai titik itu. - Baris 16–18 (
if (galat.length > 0) { throw ... }): semua galat dilaporkan sekaligus denganjoin, meniru kebiasaan compiler yang melaporkan seluruh pelanggaran tipe dalam satu kali pemeriksaan. - Baris 24–28 (
try { ... } catch): pemanggilan dengan umur bertipe string ditolak pada saat berjalan. Bandingkan dengan versi berikut, di mana penolakan terjadi sebelum program berjalan sama sekali.
Versi TypeScript dari kontrak yang sama mendeklarasikan bentuknya sekali, lalu membiarkan compiler memeriksa setiap pemanggilan:
type Pengguna = {
nama: string;
email: string;
umur: number;
};
function terimaPengguna(data: Pengguna): string {
return `Pengguna valid diterima: ${data.nama}`;
}
terimaPengguna({ nama: "Siti", email: "[email protected]", umur: "dua puluh" });Pemanggilan terakhir memuat kesalahan yang sama dengan percobaan Siti, dan compiler melaporkannya pada saat kompilasi:
error TS2322: Type 'string' is not assignable to type 'number'.Tidak ada baris program yang berjalan dengan data salah; tidak ada try/catch yang perlu ditulis untuk ini. Pemeriksaan manual di validasi-manual.js tetap berguna untuk kasus yang tidak terlihat compiler — seperti format email — tetapi pekerjaan mencegah penugasan salah jenis berpindah ke alat yang mengerjakannya konsisten.
Biaya Adopsi yang Jujur #
Adopsi TypeScript bukan gratis, dan pembiayaannya jujur dicatat supaya keputusan di chapter pertama tegas. Biaya pertama adalah kurva belajar: anotasi dasar cepat dipelajari, tetapi union, type narrowing, dan generics butuh waktu sebelum terasa alami. Biaya kedua adalah perangkat: pipeline build perlu menampung langkah kompilasi — topik chapter berikutnya. Biaya ketiga adalah disiplin: pada kode lama, tipe any bisa dipakai untuk melewati pemeriksaan apa pun, dan satu any yang menyebar membuat jaminan tipe di sekitarnya berhenti berarti.
Sebagai imbangannya, biaya itu dibayar sekali sementara pemeriksaan berjalan di setiap penyuntingan, sepanjang umur proyek. Untuk proyek yang sinyal-sinyalnya sudah memenuhi checklist chapter sebelumnya, penukaran itu terhitung menguntungkan. Pertanyaan tinggal satu: bagaimana kode .ts ini sampai menjadi JavaScript yang dijalankan? Chapter Transpilation Overview membongkar prosesnya langkah demi langkah.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
validasi-manual.js
Unduh berkas// validasi-manual.js — pemeriksaan bentuk data yang di TypeScript dilakukan
// compiler, di JavaScript murni kita tulis sendiri saat runtime.
// Jalankan di terminal: node validasi-manual.js
function terimaPengguna(data) {
const galat = [];
if (typeof data.nama !== "string" || data.nama.length === 0) {
galat.push("nama harus string tidak kosong");
}
if (typeof data.email !== "string" || !data.email.includes("@")) {
galat.push("email tanpa tanda @");
}
if (typeof data.umur !== "number") {
galat.push(`umur harus number, diterima ${typeof data.umur}`);
}
if (galat.length > 0) {
throw new Error(galat.join("; "));
}
return `Pengguna valid diterima: ${data.nama}`;
}
console.log(terimaPengguna({ nama: "Budi", email: "[email protected]", umur: 25 }));
try {
terimaPengguna({ nama: "Siti", email: "[email protected]", umur: "dua puluh" });
} catch (error) {
console.log("Ditolak saat runtime:", error.message);
}
try {
terimaPengguna({ nama: "Rina", email: "rina.example.com", umur: 19 });
} catch (error) {
console.log("Ditolak saat runtime:", error.message);
}