Di proyek ini kamu merakit hal-hal dari materi TypeScript sebelumnya jadi satu aplikasi kecil: katalog toko yang datanya bertipe dari ujung ke ujung. Bayangin gudang toko. Tiap barang punya kartu data dengan isian yang sama, kategorinya cuma boleh dari daftar tertentu, dan petugas gudang punya satu cara mencari yang bisa dipakai untuk isian apa pun. TypeScript menjaga supaya petugasnya gak mencari isian yang gak ada di kartu, dan gak mencari angka dengan teks.
🧪 Tebakan cepat: harga Pensil adalah angka
3000. Kalau fungsi pencarinya menerimavalue: any, lalu kamu memanggilfilterByKey(produk, "harga", "3000")(teks, bukan angka), apa yang terjadi: TypeScript memberi error, atau hasilnya array kosong tanpa peringatan? Tebak dulu, jawabannya ada di bagian "Satu fungsi cari untuk semua kunci".
Model data: interface dan union literal
interface Produk {
nama: string
kategori: "buku" | "alat tulis"
harga: number
adaStok: boolean
}
const produk: Produk[] = [
{ nama: "Buku Tulis", kategori: "alat tulis", harga: 5000, adaStok: true },
{ nama: "Novel", kategori: "buku", harga: 85000, adaStok: true },
{ nama: "Pensil", kategori: "alat tulis", harga: 3000, adaStok: false },
{ nama: "Kamus", kategori: "buku", harga: 120000, adaStok: false },
]
interface Produkadalah kartu datanya: tiap produk wajib punya empat isian ini, dengan tipe ini.kategori: "buku" | "alat tulis"adalah union literal: cuma dua teks itu yang boleh.Produk[]artinya array berisiProduk. Salah ketik isian atau tipe di data langsung ditolak.
Satu fungsi cari untuk semua kunci
Daripada menulis cariKategori, cariHarga dan cariStok, tulis satu fungsi generic:
function filterByKey<T, K extends keyof T>(items: T[], key: K, value: T[K]): T[] {
return items.filter((item) => item[key] === value)
}
const hasil = filterByKey(produk, "kategori", "buku")
console.log(hasil.map((p) => p.nama)) // ["Novel", "Kamus"]
<T, ...>:Tadalah tipe isi array-nya. Dariproduk, TypeScript menyimpulkanTadalahProduk.K extends keyof T:keyof Tadalah gabungan semua nama isianT, yaitu"nama" | "kategori" | "harga" | "adaStok".Kharus salah satunya.value: T[K]: tipe nilai yang dicari ikut tipe isian yang dipilih. Untuk"harga"artinyanumber, untuk"kategori"artinya"alat tulis" | "buku".items.filter(...)menyimpan isi yangitem[key]-nya sama persis (===) denganvalue.item[key], pakai kurung siku, membaca isian yang namanya ada dikey.
Bandingkan dengan versi value: any (yang ada di kode awal latihan):
| Panggilan | Hasil | value: any |
value: T[K] |
|---|---|---|---|
filterByKey(produk, "kategori", "buku") |
Novel, Kamus | boleh | boleh |
filterByKey(produk, "harga", 3000) |
Pensil | boleh | boleh |
filterByKey(produk, "harga", "3000") |
[] |
boleh | ts(2345) |
filterByKey(produk, "kategori", "majalah") |
[] |
boleh | ts(2345) |
filterByKey(produk, "hraga", 3000) |
[] |
ts(2345) | ts(2345) |
Dengan value: any, "3000" lolos, dan hasilnya array kosong tanpa peringatan, karena angka 3000 gak sama persis dengan teks "3000". Itu jawaban tebakannya. Dengan value: T[K], TypeScript menolak sebelum kode jalan: Argument of type 'string' is not assignable to parameter of type 'number'. ts(2345). Untuk "majalah": Argument of type '"majalah"' is not assignable to parameter of type '"alat tulis" | "buku"'. Salah ketik nama kunci tertangkap di kedua versi, berkat keyof: Argument of type '"hraga"' is not assignable to parameter of type 'keyof Produk'.
Mengubah dan mencari dengan aman
function ubahProduk(p: Produk, perubahan: Partial<Produk>): Produk {
return { ...p, ...perubahan }
}
ubahProduk(produk[0], { harga: 4500 }) // boleh, cuma harga yang diubah
ubahProduk(produk[0], { harga: "murah" }) // error ts(2322)
const cari = produk.find((p) => p.nama === "Pensil")
if (cari) {
console.log(cari.harga) // 3000
}
Partial<Produk>membuat semua isianProdukjadi opsional, tapi tipenya tetap:{ harga: "murah" }ditolak denganType 'string' is not assignable to type 'number'.ts(2322).findmengembalikanProduk | undefined. Tanpaif (cari),cari.hargaditolak:'cari' is possibly 'undefined'.ts(18048). Di dalamif, TypeScript tahucaripastiProduk.
Menjalankan proyeknya
Proyeknya diatur oleh tsconfig.json, dengan "strict": true supaya semua pemeriksaan ketat nyala. Perintah npx tsc memeriksa semua file, lalu menulis JavaScript-nya. Semua tipe hilang, fungsinya tinggal begini:
function filterByKey(items, key, value) {
return items.filter((item) => item[key] === value);
}
Versi value: any dan value: T[K] jadi JavaScript yang sama persis. Bedanya cuma di apa yang ditolak tsc sebelum kode jalan.
⚠️ Jebakan yang sering ketemu
value: any. Kodenya jalan, tapi pencarian dengan tipe yang salah lolos diam-diam dan hasilnya[].anymematikan pemeriksaan di tempat itu.item.keybukanitem[key].item.keymembaca isian yang namanya persiskey, yang gak ada. Waktu jalan, hasilnya selalu[].finddipakai tanpa dicek. Hasilnya bisaundefined. Cek denganifdulu.- Di latihan, error tipe bikin gagal. Pemeriksa TypeScript jalan dulu (mode
strict, sepertitsc --noEmit), lalu kodenya dijalankan dan hasil serta teks kodenya dicek. HasilfilterByKeyharus persis sama dengan yang diminta, dan katakeyofserta anotasi tipe dari kode awal harus tetap ada.
TL;DR: Proyek type-safe dimulai dari model data: interface untuk bentuknya, union literal untuk nilai yang terbatas. Fungsi generic filterByKey<T, K extends keyof T>(items: T[], key: K, value: T[K]): T[] dengan return items.filter((item) => item[key] === value) bekerja untuk data apa pun: keyof menolak nama kunci yang gak ada, T[K] menolak nilai yang tipenya salah, sedangkan value: any meloloskannya diam-diam. Partial<T> untuk perubahan sebagian, dan hasil find dicek dengan if. Semuanya diatur tsconfig.json dengan "strict": true, diperiksa dan dikompilasi dengan npx tsc, dan tipenya hilang di JavaScript.