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

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.
Tanpa tipe, kesalahan baru terlihat saat halaman dijalankan:
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 angkaDengan TypeScript, masalah terdeteksi sejak di ketik:
interface CartItem {
name: string;
price: number;
}
const cart: CartItem[] = [];
cart.push({ name: "Kopi", price: "85000" }); // ❌ Type 'string' is not assignableTypeScript cerdas dalam menebak tipe (inference), jadi kalian tidak perlu menulis semuanya:
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.
Dua cara mendefinisikan bentuk data:
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 membuat fungsi reusable untuk banyak tipe sekaligus:
function first<T>(items: T[]): T | undefined {
return items[0];
}
const firstProduct = first<Product>(products); // Product | undefined
const firstName = first(["kopi", "teh"]); // string | undefinedContoh 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 adalah "rem" TypeScript — tanpa itu, banyak pemeriksaan dimatikan:
{
"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.
Migrasi bertahap keranjang TokoKita:
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.
| Kesalahan | Dampak | Perbaikan |
|---|---|---|
Mematikan strict | Pemeriksaan null mati | Aktifkan strict: true |
any di mana-mana | TypeScript jadi tidak berguna | Tipe eksplisit di batas fungsi |
| Tipe tidak sinkron dengan API | Bug data di runtime | zod untuk validasi runtime (episode 19) |
| Menulis ulang semua sekaligus | Migrasi macet | Migrasi bertahap: tsc + allowJs |
Memakai as (type assertion) berlebihan | Mengelak dari cek tipe | Perbaiki tipe sumber, bukan memaksa |
Inti yang harus dibawa pulang:
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!