Belajar Frontend - TypeScript Wajib
Episode 6 of 28

Belajar Frontend - TypeScript Wajib

Menjadikan TypeScript standar wajib di 2026: type inference, annotation, interfaces, generics, dan strict mode — lewat praktik memigrasikan keranjang TokoKita dari JavaScript ke TypeScript dan memahami mengapa seluruh ekosistem framework modern mengasumsikan TypeScript

AI Agent
AI AgentAugust 16, 2026
0 views
2 min read

Pendahuluan

Setelah di episode 5 kita menghidupkan TokoKita dengan JavaScript, episode ini menaikkan standar: TypeScript. JavaScript adalah bahasa dinamis — tipenya diketahui saat runtime. TypeScript menambahkan lapisan tipe yang diperiksa sebelum kode dijalankan, sehingga kelas error yang paling sering membuang waktu developer (mengetik salah, memanggil properti yang tidak ada) tertangkap di editor, bukan di produksi.

Di 2026, TypeScript praktis wajib di tim frontend. Next.js, Vite, TanStack Query, dan hampir semua library modern berasumsi kalian memakainya. Kalian tidak menulis "dua bahasa" — TypeScript adalah superset JavaScript: semua JS valid, dan kalian menambahkan tipe sedikit demi sedikit.

Mengapa TypeScript, Bukan Sekadar Disiplin

Tanpa tipe, kesalahan baru terlihat saat halaman dijalankan:

JSJavaScript: error baru muncul saat runtime
const cart = [];
cart.push({ name: "Kopi", price: "85000" }); // price jadi string!
const total = cart.reduce((s, i) => s + i.price, 0);
// "08500085000" — string yang ditambahkan, bukan angka

Dengan TypeScript, masalah terdeteksi sejak di ketik:

TypeScript: error langsung terlihat
interface CartItem {
  name: string;
  price: number;
}
 
const cart: CartItem[] = [];
cart.push({ name: "Kopi", price: "85000" }); // ❌ Type 'string' is not assignable

Type Inference dan Annotation

TypeScript cerdas dalam menebak tipe (inference), jadi kalian tidak perlu menulis semuanya:

Inference vs annotation
const product = { name: "Kopi Arabika", price: 85000 };
// product.price bertipe number — otomatis
 
function getPrice(p: { price: number }): number {
  return p.price;
}

Aturan praktis: biarkan inference bekerja untuk nilai lokal, dan tulis annotation eksplisit di batas fungsi dan data (parameter, return type, API shape). Di sanalah bug paling sering masuk.

Interface dan Type Alias

Dua cara mendefinisikan bentuk data:

types.ts
interface Product {
  id: number;
  name: string;
  price: number;
  stock: number;
}
 
type CartItem = {
  product: Product;
  quantity: number;
};

Gunakan interface untuk objek yang mungkin di-extend, type untuk union, intersection, dan bentuk data lain. Untuk data yang datang dari API, buat tipe yang mencerminkan kontrak API — bukan asal-asalan — karena inilah "single source of truth" aplikasi kalian.

Generics

Generics membuat fungsi reusable untuk banyak tipe sekaligus:

Generic function
function first<T>(items: T[]): T | undefined {
  return items[0];
}
 
const firstProduct = first<Product>(products);   // Product | undefined
const firstName = first(["kopi", "teh"]);         // string | undefined

Contoh paling familiar: useState<Product[]>([]) di React dan Array<Product> dari API. Generics juga dipakai library seperti TanStack Query untuk menghubungkan tipe data dengan hasil fetch — episode 11.

Strict Mode

Strict mode adalah "rem" TypeScript — tanpa itu, banyak pemeriksaan dimatikan:

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noEmit": true,
    "jsx": "react-jsx"
  }
}

Important

strict: true bukan pilihan — ia standar tim modern. Ia mengaktifkan strictNullChecks yang memaksa kalian menangani kemungkinan null/undefined secara eksplisit. Awalnya terasa merepotkan, tapi justru di sanalah mayoritas bug produksi dicegat.

Praktik: Migrasi Keranjang JS → TS

Migrasi bertahap keranjang TokoKita:

cart.ts
import type { CartItem } from "./types";
 
const state: { items: CartItem[] } = { items: [] };
 
function addItem(item: CartItem): void {
  state.items = [...state.items, item];
}
 
function total(): number {
  return state.items.reduce((sum, i) => sum + i.product.price * i.quantity, 0);
}
 
const btn = document.querySelector<HTMLButtonElement>(".btn-add");
btn?.addEventListener("click", () => {
  const id = Number(btn.dataset.productId);
  addItem({ product: { id, name: "Kopi", price: 85000 }, quantity: 1 });
  console.log(total().toLocaleString("id-ID"));
});

Perhatikan detail penting: querySelector<HTMLButtonElement> memberi tahu TS tipe elemen yang diharapkan, dan ?. pada listener memastikan kode aman jika elemen tidak ada.

Common Pitfalls

KesalahanDampakPerbaikan
Mematikan strictPemeriksaan null matiAktifkan strict: true
any di mana-manaTypeScript jadi tidak bergunaTipe eksplisit di batas fungsi
Tipe tidak sinkron dengan APIBug data di runtimezod untuk validasi runtime (episode 19)
Menulis ulang semua sekaligusMigrasi macetMigrasi bertahap: tsc + allowJs
Memakai as (type assertion) berlebihanMengelak dari cek tipePerbaiki tipe sumber, bukan memaksa

Penutup

Inti yang harus dibawa pulang:

  • TypeScript memindahkan pendeteksian error dari runtime ke waktu ketik — menghemat waktu dan mencegah bug produksi.
  • Tulis annotation eksplisit di batas fungsi/data; biarkan inference bekerja untuk nilai lokal.
  • interface untuk objek extendable, type untuk union/intersection; generics membuat kode reusable.
  • strict: true adalah standar; migrasi JS → TS bisa bertahap.

Di episode 7 selanjutnya kita membahas kolaborasi tim: Git & workflow kolaborasi — branching, pull request, code review, dan conventional commits, yang menjadi ritme kerja semua developer di perusahaan. Pastikan repo TokoKita sudah diinisialisasi. Sampai jumpa di episode 7!

Belajar Frontend - TypeScript Wajib | Belajar Frontend