TypeScript di Dunia Nyata: React, Node & Praktik Terbaik
Gambaran memakai TypeScript di React, Node/Express, dan DOM; satisfies, tipe untuk props, kamus error umum, dan daftar praktik terbaik untuk kode yang mudah dirawat.
TypeScript hampir ada di mana-mana
Next.js, Angular, NestJS, Deno, dan banyak pustaka besar ditulis dengan TypeScript. Vue 3 dan React punya dukungan kelas satu. Bab ini memberi gambaran bagaimana ilmu yang sudah kamu pelajari muncul di proyek sungguhan.
1. React + TypeScript
File berakhiran .tsx. Props komponen diberi tipe lewat type atau interface:
type KartuProps = {
judul: string
ukuran?: "kecil" | "besar" // literal union untuk pilihan terbatas
onKlik?: () => void // callback opsional
children?: React.ReactNode
}
export function Kartu({ judul, ukuran = "kecil", onKlik, children }: KartuProps) {
return (
<div className={ukuran} onClick={onKlik}>
<h2>{judul}</h2>
{children}
</div>
)
}
// <Kartu judul="Promo" ukuran="sedang" /> ❌ "sedang" tidak ada di pilihan
const [hitung, setHitung] = useState(0) // number (inference)
const [user, setUser] = useState<Pengguna | null>(null) // generics untuk nilai awal null
const ref = useRef<HTMLInputElement>(null)
function ubah(e: React.ChangeEvent<HTMLInputElement>) { console.log(e.target.value) }
2. Node.js + Express
npm i express
npm i -D typescript tsx @types/node @types/express
import express, { Request, Response } from "express"
const app = express()
app.use(express.json())
interface BodyDaftar { nama: string; email: string }
app.post("/daftar", (req: Request<{}, {}, BodyDaftar>, res: Response) => {
const { nama, email } = req.body // bertipe BodyDaftar
res.status(201).json({ pesan: `Halo ${nama}` })
})
app.listen(3000)
Ingat bab 22: tipe pada req.body adalah klaim — validasi isinya (mis. dengan Zod) sebelum dipercaya.
3. DOM di browser
const tombol = document.querySelector("#kirim") // Element | null
tombol?.addEventListener("click", () => console.log("klik"))
const input = document.querySelector<HTMLInputElement>("#nama") // generics → HTMLInputElement | null
if (input) console.log(input.value) // wajib cek null dulu
4. Pola yang membuat kode mudah dirawat
| Praktik | Alasan |
|---|---|
Nyalakan strict sejak hari pertama | Bug null/any tertangkap awal |
Hindari any; pakai unknown + narrowing | Proteksi tipe tidak bocor |
| Biarkan inference bekerja; tulis tipe di batas fungsi | Kode ringkas tapi API jelas |
| Model data dengan discriminated union | Status mustahil jadi tidak mungkin dibuat |
Turunkan tipe (typeof, keyof, utility types) | Satu sumber kebenaran |
| Validasi data dari luar (Zod / guard) | Tipe tidak otomatis menjamin runtime |
Hindari as dan ! bila ada alternatif | Keduanya "mematikan" pemeriksaan |
Jalankan tsc --noEmit + ESLint di CI | Kesalahan tidak lolos ke produksi |
5. "Make illegal states unrepresentable"
Prinsip emas desain tipe: buat tipe yang tidak bisa mengungkapkan kondisi yang salah.
// ❌ boleh sukses sekaligus ada error, atau keduanya kosong
type StateBuruk = { memuat: boolean; data?: string[]; error?: string }
// ✅ tepat satu kemungkinan pada satu waktu
type StateBaik =
| { status: "diam" }
| { status: "memuat" }
| { status: "sukses"; data: string[] }
| { status: "gagal"; error: string }
6. Kamus error yang sering muncul
| Pesan | Biasanya berarti |
|---|---|
| Type 'X' is not assignable to type 'Y' | Nilai tidak cocok dengan tipe yang diharapkan |
| Property 'p' does not exist on type 'T' | Typo, atau perlu narrowing / properti belum dideklarasikan |
| Object is possibly 'undefined' / 'null' | Tangani kasus kosong (?., ??, if) |
| Parameter 'x' implicitly has an 'any' type | Tambahkan tipe pada parameter |
| Argument of type 'A' is not assignable to parameter of type 'B' | Argumen salah tipe |
| Cannot find name 'x' | Belum diimpor/dideklarasikan, atau lib belum memuat tipenya |
Cara membaca pesan error panjang
Mulai dari baris paling atas (ringkasan masalah) dan baris paling bawah (penyebab paling dalam). Bagian tengah biasanya hanya jejak rantai tipe.
Kesalahan umum pemula
- Menyalin tipe dari mana-mana sehingga duplikat dan tidak sinkron.
- Menambah
// @ts-ignoreuntuk membungkam error. Gunakan@ts-expect-errordengan alasan, dan hanya bila terpaksa. - Terlalu cepat membuat tipe super-rumit sebelum kebutuhan jelas.