TypeScript untuk Pemula: JavaScript yang Lebih Aman
TypeScript menangkap banyak kesalahan JavaScript sebelum kodenya dijalankan. Kamu akan memasangnya, memahami pesan errornya, dan menulis program keranjang belanja bertipe.
Oleh Afa Hernandes12 menit baca
Daftar isi
- Sebelum mulai
- Langkah 1: Siapkan proyek
- Langkah 2: Tipe pertamamu
- Node menjalankan, tsc memeriksa
- Langkah 3: Tipe dasar dan inferensi
- Langkah 4: Bentuk data dengan interface
- Langkah 5: Pilihan nilai dengan union type
- Langkah 6: Menangani nilai yang bisa kosong
- Langkah 7: Program keranjang belanja
- type atau interface?
- Error yang sering muncul
- Langkah berikutnya: rilis dan amankan
- Pertanyaan yang sering diajukan
- Apakah TypeScript menggantikan JavaScript?
- Apakah kode TypeScript berjalan lebih cepat?
- Bolehkah memakai any saat bingung menentukan tipe?
- Perlu belajar TypeScript kalau sudah paham JavaScript?
- Kesimpulan
JavaScript membiarkan banyak kesalahan lolos sampai program dijalankan, dan kadang tetap lolos tanpa error sama sekali. Coba program kecil ini:
function hitungTotal(harga, jumlah) { return harga * jumlah;}
const hargaDariForm = "18000"; // nilai dari <input> selalu berupa teksconsole.log(hitungTotal(hargaDariForm, 2));console.log(hitungTotal(hargaDariForm + 2000, 2));console.log(hitungTotal(18000));36000360004000NaNBaris pertama kebetulan benar. Baris kedua menghasilkan angka yang ngawur karena "18000" + 2000 menyambung teks menjadi "180002000". Baris ketiga lupa satu argumen dan menghasilkan NaN (Not a Number). Tidak ada satu pun pesan error. Di aplikasi sungguhan, kesalahan seperti ini baru ketahuan saat pelanggan protes totalnya salah.
TypeScript adalah JavaScript yang ditambah tipe data. Kamu menuliskan bahwa harga harus berupa angka, dan TypeScript memeriksa seluruh kodemu sebelum dijalankan. Ketiga kesalahan di atas langsung ketahuan. Di tutorial ini kamu akan memasang TypeScript, mengenal tipe-tipe yang paling sering dipakai, dan membuat program keranjang belanja yang tipenya lengkap.
Sebelum mulai
- Sudah paham JavaScript modern:
const, arrow function, array method, dan object. TypeScript hanya menambahkan tipe di atasnya. - Node.js versi LTS dari nodejs.org. Cek dengan
node -v. - Diuji dengan Node 24 dan TypeScript 7.0.
Langkah 1: Siapkan proyek
Buat folder proyek, lalu pasang TypeScript di dalamnya:
mkdir belajar-tscd belajar-tsnpm init -ynpm pkg set type=modulenpm install --save-dev typescriptnpm init -ymembuatpackage.json, file yang mencatat informasi proyek dan paket yang dipakainya.npm pkg set type=modulemembuat setiap file di proyek ini diperlakukan sebagai module JavaScript modern, sama seperti<script type="module">di browser.--save-devmenandai TypeScript sebagai alat untuk developer, bukan bagian dari program yang dijalankan pengguna.
Lalu buat file konfigurasi tsconfig.json:
{ "compilerOptions": { "target": "esnext", "module": "nodenext", "strict": true, "noEmit": true, "erasableSyntaxOnly": true, "verbatimModuleSyntax": true }}Opsi yang paling penting:
"strict": truemenyalakan semua pemeriksaan yang ketat. Selalu nyalakan untuk proyek baru. Tanpa ini, banyak kesalahan dibiarkan lewat."noEmit": trueartinya TypeScript hanya memeriksa, tidak menghasilkan file.js. Menjalankan programnya diserahkan ke Node."erasableSyntaxOnly": truemelarang fitur TypeScript yang tidak bisa dijalankan langsung oleh Node. Penjelasannya ada di bagian error di bawah.
Perintah npx tsc --init juga bisa membuat tsconfig.json, tapi hasilnya lebih panjang dengan banyak opsi yang belum kamu perlukan. Versi pendek di atas cukup untuk tutorial ini.
Terakhir, tambahkan dua perintah pintas ke package.json:
npm pkg set scripts.cek="tsc" scripts.start="node src/keranjang.ts"Sekarang npm run cek memeriksa semua file TypeScript di proyek, dan npm start menjalankan program utamanya. Buat juga folder src untuk menyimpan kode.
Langkah 2: Tipe pertamamu
Tulis ulang hitungTotal dengan tipe:
function hitungTotal(harga: number, jumlah: number): number { return harga * jumlah;}
const hargaDariForm = "18000";console.log(hitungTotal(hargaDariForm, 2));console.log(hitungTotal(18000));harga: number artinya parameter harga harus berupa angka. ): number setelah tanda kurung artinya function ini mengembalikan angka. Sekarang periksa:
npm run ceksrc/total.ts(6,25): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.src/total.ts(7,13): error TS2554: Expected 2 arguments, but got 1.Dua kesalahan yang tadi lolos diam-diam sekarang tertangkap, lengkap dengan lokasinya: (6,25) artinya baris 6, kolom 25. Di VS Code kamu bahkan tidak perlu menjalankan perintah apa pun. Bagian yang salah langsung diberi garis bergelombang merah saat kamu mengetik.
Perbaiki dengan mengubah teks menjadi angka secara eksplisit, dan hapus baris yang lupa argumen:
function hitungTotal(harga: number, jumlah: number): number { return harga * jumlah;}
const hargaDariForm = "18000";console.log(hitungTotal(Number(hargaDariForm), 2));Jalankan npm run cek lagi. Kalau tidak ada output, berarti tidak ada error. Lalu jalankan programnya:
node src/total.ts36000Node menjalankan, tsc memeriksa
Node versi baru bisa menjalankan file .ts secara langsung. Caranya dengan membuang semua penanda tipe, lalu menjalankan sisanya sebagai JavaScript biasa. Konsekuensinya penting: Node tidak memeriksa tipe. Kalau versi total.ts yang masih salah tadi dijalankan dengan node, hasilnya tetap 36000 dan NaN tanpa protes.
Jadi alurnya selalu dua langkah: npm run cek untuk memeriksa, lalu node untuk menjalankan. Di framework seperti Astro atau Next.js, pemeriksaan ini biasanya dijalankan otomatis saat build.
Langkah 3: Tipe dasar dan inferensi
let nama: string = "Sari";let umur: number = 21;let aktif: boolean = true;let hobi: string[] = ["ngopi", "ngoding"];
let kota = "Bandung"; // TypeScript menyimpulkan tipenya: string
console.log(nama, umur, aktif, hobi, kota);| Tipe | Isi | Contoh |
|---|---|---|
string |
teks | "Sari" |
number |
angka, bulat maupun desimal | 21, 1.62 |
boolean |
benar atau salah | true, false |
string[] |
array berisi teks | ["ngopi", "ngoding"] |
null |
sengaja dikosongkan | null |
Perhatikan baris let kota = "Bandung". Tipenya tidak ditulis, tapi TypeScript menyimpulkannya sendiri dari nilai awalnya. Ini disebut inferensi tipe. Kalau nanti kamu menulis kota = 2026;, TypeScript tetap menolak:
error TS2322: Type 'number' is not assignable to type 'string'.Karena itu, kamu tidak perlu menulis tipe di semua tempat. Kebiasaan yang umum: tulis tipe di parameter function dan di bentuk data (bagian berikutnya), lalu biarkan TypeScript menyimpulkan sisanya.
Langkah 4: Bentuk data dengan interface
Data di aplikasi web kebanyakan berupa object. interface mendeskripsikan bentuknya: properti apa saja yang ada dan apa tipenya.
interface Produk { id: number; nama: string; harga: number; // dalam rupiah, tanpa desimal diskon?: number; // opsional, dalam persen}
const kopiSusu: Produk = { id: 1, nama: "Kopi susu", harga: 18000 };Tanda ? setelah diskon artinya properti itu opsional: boleh ada, boleh tidak. Properti lainnya wajib. Lupa satu properti, atau salah ketik nama method, langsung ketahuan:
const teh: Produk = { id: 3, nama: "Teh" };console.log(kopiSusu.nama.toUppercase());error TS2741: Property 'harga' is missing in type '{ id: number; nama: string; }' but required in type 'Produk'.error TS2551: Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?Bonusnya: setelah interface ditulis, VS Code tahu persis isi setiap object. Ketik kopiSusu. dan editor langsung menawarkan id, nama, harga, dan diskon.
Langkah 5: Pilihan nilai dengan union type
Status pesanan hanya boleh salah satu dari beberapa nilai. Dengan tanda | (dibaca “atau”), kamu bisa membuat tipe yang membatasi pilihannya:
type Status = "draft" | "dibayar" | "dikirim";
let status: Status = "draft";status = "dibayar";status = "dibayr";error TS2820: Type '"dibayr"' is not assignable to type 'Status'. Did you mean '"dibayar"'?Di JavaScript biasa, salah ketik "dibayr" akan lolos dan baru ketahuan saat pesanan tidak pernah muncul di daftar “dibayar”. Di TypeScript, kesalahan itu tertangkap bahkan sebelum kamu menyimpan file.
type membuat nama baru untuk sebuah tipe. Union type juga bisa menggabungkan tipe yang berbeda, misalnya string | null untuk teks yang boleh kosong.
Langkah 6: Menangani nilai yang bisa kosong
Salah satu error paling sering di JavaScript adalah memakai nilai yang ternyata null. Dengan strict, TypeScript memaksa kamu memikirkannya:
function panjangCatatan(catatan: string | null): number { return catatan.length;}error TS18047: 'catatan' is possibly 'null'.Solusinya, periksa dulu:
function panjangCatatan(catatan: string | null): number { if (catatan === null) { return 0; } return catatan.length;}
console.log(panjangCatatan("Gula sedikit"));console.log(panjangCatatan(null));120Setelah if (catatan === null) return …, TypeScript tahu bahwa di baris berikutnya catatan pasti berupa string. Proses mempersempit tipe seperti ini disebut narrowing. Hal yang sama berlaku untuk properti opsional: produk.diskon bertipe number | undefined, jadi kamu harus memeriksanya sebelum dipakai untuk menghitung.
Langkah 7: Program keranjang belanja
Sekarang gabungkan semuanya. Program ini menghitung pesanan di kedai Kopi Senja, sama seperti keranjang di tutorial JavaScript, tapi kali ini setiap data punya tipe yang jelas:
type Status = "draft" | "dibayar" | "dikirim";
interface Produk { id: number; nama: string; harga: number; // dalam rupiah, tanpa desimal diskon?: number; // opsional, dalam persen}
interface ItemKeranjang { produk: Produk; jumlah: number;}
interface Pesanan { pelanggan: string; items: ItemKeranjang[]; status: Status; catatan: string | null;}
function hargaSetelahDiskon(produk: Produk): number { if (produk.diskon === undefined) { return produk.harga; } return Math.round(produk.harga * (1 - produk.diskon / 100));}
function totalPesanan(pesanan: Pesanan): number { return pesanan.items.reduce( (total, item) => total + hargaSetelahDiskon(item.produk) * item.jumlah, 0, );}
function formatRupiah(nilai: number): string { return "Rp" + nilai.toLocaleString("id-ID");}
function labelStatus(status: Status): string { switch (status) { case "draft": return "Belum dibayar"; case "dibayar": return "Sedang dikemas"; case "dikirim": return "Dalam perjalanan"; }}
const kopiSusu: Produk = { id: 1, nama: "Kopi susu", harga: 18000 };const croissant: Produk = { id: 2, nama: "Croissant", harga: 25000, diskon: 20 };
const pesanan: Pesanan = { pelanggan: "Sari", items: [ { produk: kopiSusu, jumlah: 2 }, { produk: croissant, jumlah: 1 }, ], status: "dibayar", catatan: null,};
console.log(`Pesanan ${pesanan.pelanggan}: ${labelStatus(pesanan.status)}`);for (const item of pesanan.items) { const subtotal = hargaSetelahDiskon(item.produk) * item.jumlah; console.log(`- ${item.jumlah}x ${item.produk.nama}: ${formatRupiah(subtotal)}`);}console.log(`Total: ${formatRupiah(totalPesanan(pesanan))}`);console.log(`Catatan: ${pesanan.catatan ?? "-"}`);npm run cek memeriksa semua file di proyek. Kalau ada file latihan dari langkah sebelumnya yang masih berisi kode yang sengaja salah, perbaiki atau hapus dulu. Lalu periksa dan jalankan:
npm run ceknpm startPesanan Sari: Sedang dikemas- 2x Kopi susu: Rp36.000- 1x Croissant: Rp20.000Total: Rp56.000Catatan: -Beberapa hal yang patut diperhatikan:
- Interface bisa bersarang.
Pesananberisi arrayItemKeranjang, dan setiapItemKeranjangberisiProduk. Bentuk datanya terbaca dari atas tanpa perlu menebak. labelStatustidak butuhdefault. TypeScript tahuStatushanya punya tiga kemungkinan dan ketiganya sudah ditangani. Kalau suatu hari kamu menambah status"dibatalkan"tapi lupa menambahcase-nya,npm run ceklangsung protes:error TS2366: Function lacks ending return statement and return type does not include 'undefined'.- Parameter di dalam
reducetidak perlu diberi tipe. TypeScript menyimpulkanitemsebagaiItemKeranjangdari tipepesanan.items.
type atau interface?
Untuk mendeskripsikan bentuk object, keduanya hampir sama. Ini juga sah:
type Produk = { id: number; nama: string; harga: number; diskon?: number;};Aturan praktis yang dipakai banyak tim: interface untuk bentuk object, type untuk union dan hal lain seperti type Status = "draft" | "dibayar". Yang lebih penting dari pilihannya adalah konsisten dalam satu proyek.
Error yang sering muncul
error TS2345: Argument of type ‘string’ is not assignable to parameter of type ‘number’.
Kamu mengirim teks ke parameter yang meminta angka. Sering terjadi dengan nilai dari form atau URL. Ubah dulu dengan Number(nilai), lalu pastikan hasilnya bukan NaN sebelum dipakai.
error TS2554: Expected 2 arguments, but got 1.
Jumlah argumen tidak sesuai dengan parameter function. Lengkapi argumennya, atau jadikan parameternya opsional dengan ? kalau memang boleh tidak diisi.
error TS2741: Property ‘harga’ is missing in type …
Object yang kamu buat tidak punya properti yang diwajibkan oleh interface-nya. Tambahkan propertinya, atau beri ? di interface kalau properti itu memang opsional.
error TS18048: ‘produk.diskon’ is possibly ‘undefined’.
Kamu memakai properti opsional tanpa memeriksanya. Tambahkan pemeriksaan seperti di hargaSetelahDiskon, atau beri nilai cadangan dengan produk.diskon ?? 0.
error TS7006: Parameter ‘data’ implicitly has an ‘any’ type.
Parameter function belum diberi tipe, sehingga TypeScript tidak bisa memeriksanya. Tuliskan tipenya, misalnya (data: Produk). Jangan menambal dengan any, karena any mematikan semua pemeriksaan untuk nilai itu.
error TS1294: This syntax is not allowed when ‘erasableSyntaxOnly’ is enabled.
Biasanya muncul saat memakai enum. Node tidak bisa menjalankan enum dengan cara membuang tipe saja, dan kalau tetap dijalankan, hasilnya SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode. Ganti dengan union type seperti type Status = "draft" | "dibayar", yang hasilnya sama dan lebih ringkas.
error TS5112: tsconfig.json is present but will not be loaded if files are specified on commandline.
Kamu menjalankan npx tsc nama-file.ts. Kalau ada tsconfig.json, jalankan npx tsc (atau npm run cek) tanpa nama file, supaya pengaturan di tsconfig.json ikut dipakai.
Langkah berikutnya: rilis dan amankan
Satu hal yang sering disalahpahami: tipe TypeScript hilang saat program berjalan. TypeScript hanya memeriksa kode yang kamu tulis. Data yang datang dari luar, seperti isi form, respons API, atau file JSON, tidak ikut diperiksa saat program berjalan. Kalau API mengirim harga: "18000" padahal interface-mu bilang number, TypeScript tidak akan tahu. Data dari luar tetap harus divalidasi, terutama di server. Kebiasaan ini akan banyak dipakai saat membuat API di level berikutnya, dan alasannya dijelaskan di OWASP Top 10.
Untuk merilis, browser tidak bisa menjalankan file .ts secara langsung. Framework modern seperti Astro dan Next.js mengurus pengubahan ke JavaScript saat build, dan hasilnya bisa di-deploy seperti biasa lewat deploy pertama ke Cloudflare Pages. Simpan proyekmu di GitHub dengan Git, dan pastikan folder node_modules masuk .gitignore.
Pertanyaan yang sering diajukan
Apakah TypeScript menggantikan JavaScript?
Tidak. TypeScript adalah JavaScript plus tipe. Semua yang kamu pelajari di JavaScript tetap berlaku, dan setelah tipe dibuang, yang berjalan adalah JavaScript biasa.
Apakah kode TypeScript berjalan lebih cepat?
Tidak. Setelah tipe dibuang, kodenya sama dengan JavaScript. Keuntungan TypeScript ada di saat menulis kode: kesalahan ketahuan lebih awal, dan editor bisa memberi saran yang jauh lebih akurat.
Bolehkah memakai any saat bingung menentukan tipe?
Sebaiknya tidak. any membuat TypeScript berhenti memeriksa nilai itu, sehingga kamu kembali ke JavaScript tanpa pengaman. Kalau tipe datanya memang belum diketahui, pakai unknown, yang memaksa kamu memeriksa isinya dulu sebelum dipakai.
Perlu belajar TypeScript kalau sudah paham JavaScript?
Kalau kamu ingin bekerja dengan framework modern atau di tim, ya. Banyak proyek dan contoh di dokumentasi framework sekarang ditulis dalam TypeScript. Kabar baiknya, dasar yang ada di tutorial ini sudah cukup untuk membaca sebagian besar kode TypeScript sehari-hari.
Kesimpulan
TypeScript menambahkan tipe ke JavaScript supaya banyak kesalahan, seperti salah tipe, argumen kurang, salah ketik, dan nilai yang ternyata kosong, ketahuan sebelum kode dijalankan. Dengan strict, interface, union type, dan narrowing, kamu sudah memegang alat yang paling sering dipakai. Ingat alurnya: tsc memeriksa, Node menjalankan.
Dengan ini Level 1 jalur Web Developer Modern selesai: HTML dan CSS, JavaScript, dan TypeScript. Level berikutnya membahas cara berpikir dalam komponen dan memilih framework modern.



