Generics sering dianggap topik yang menakutkan buat pemula, padahal konsepnya sederhana banget kalau dijelasin pake analogi yang pas. Artikel ini mulai dari masalah nyata yang diselesain generics, yaitu bikin fungsi atau komponen yang reusable tanpa kehilangan informasi tipe. Pembaca bakal diajak bangun pemahaman step by step, dari generic function sederhana, generic interface, sampai penggunaan `extends` buat batasin tipe apa aja yang boleh masuk, dan default type parameter biar generic lebih fleksibel. Semua dijelasin pake contoh kode dunia nyata kayak fungsi fetch data API dan komponen wrapper.
Timur Dian Radha Sejati
Founder SejatiDimedia•25 September 2026•5 menit baca
Silabus Seri Rekayasa
TypeScript Fundamentals
Series ini dirancang untuk membangun fondasi TypeScript yang kuat bagi pembaca yang baru mulai belajar atau ingin memperkuat pemahaman dasarnya. Dimulai dari alasan mendasar kenapa TypeScript layak dipelajari dibanding JavaScript murni, lanjut ke konsep-konsep inti seperti perbedaan any, unknown, dan never, cara kerja type inference, union dan intersection type, generics, hingga utility types yang paling sering dipakai di proyek nyata. Setiap artikel ditulis dengan pendekatan step by step, disertai contoh kode dan studi kasus dunia nyata, sehingga pembaca tidak hanya tahu "apa" tapi juga paham "kenapa" di balik setiap konsep. Series ini menjadi pondasi sebelum masuk ke topik yang lebih advance seperti type level programming dan pola arsitektur TypeScript di Series berikutnya.
Coba bayangin kamu punya kotak perkakas dengan satu kunci pas yang bentuknya bisa nyesuain sendiri, entah itu buat baut kecil, baut gede, atau bentuk yang aneh sekalipun. Satu alat, tapi tetep pas dipake buat banyak kebutuhan berbeda, tanpa kamu harus punya kunci pas terpisah buat tiap ukuran. Nah, generics di TypeScript itu kurang lebih kayak gitu, satu fungsi atau tipe yang bisa "nyesuain diri" sesuai tipe data yang kamu kasih, tapi tetep type safe.
Masalah yang Diselesain Generics
Bayangin kamu bikin fungsi sederhana buat ngambil elemen pertama dari sebuah array.
index.tstypescript
1
functiongetFirst(arr:any[]){
2
return arr[0];
3
}
4
5
const angka =getFirst([1,2,3]);// tipe: any
6
const nama =getFirst(["Andi","Budi"]);// tipe: any
6 baris•153 chars
UTF-8•Spaces: 4
Fungsi ini emang jalan, tapi ada masalah gede. Hasil return-nya selalu
PLAINTEXT Snippetplaintext
1
any
1 baris•3 chars
UTF-8•Spaces: 4
, gak peduli apa isi array yang kamu masukin. Padahal secara logika, kalau kamu masukin array angka, harusnya hasilnya juga bertipe
PLAINTEXT Snippetplaintext
1
number
1 baris•6 chars
UTF-8•Spaces: 4
. Kalau kamu masukin array string, harusnya hasilnya
PLAINTEXT Snippetplaintext
1
string
1 baris•6 chars
UTF-8•Spaces: 4
. Fungsi di atas gak bisa "inget" hubungan antara tipe input dan tipe output.
Coba solusiin pake generic:
index.tstypescript
1
functiongetFirst<T>(arr:T[]):T{
2
return arr[0];
3
}
4
5
const angka =getFirst([1,2,3]);// tipe: number
6
const nama =getFirst(["Andi","Budi"]);// tipe: string
6 baris•163 chars
UTF-8•Spaces: 4
PLAINTEXT Snippetplaintext
1
T
1 baris•1 chars
UTF-8•Spaces: 4
di sini adalah type parameter, semacam "variabel" tapi buat tipe data, bukan buat nilai. Pas kamu manggil
PLAINTEXT Snippetplaintext
1
getFirst([1, 2, 3])
1 baris•19 chars
UTF-8•Spaces: 4
, TypeScript otomatis nebak
PLAINTEXT Snippetplaintext
1
T
1 baris•1 chars
UTF-8•Spaces: 4
itu
PLAINTEXT Snippetplaintext
1
number
1 baris•6 chars
UTF-8•Spaces: 4
, terus dia tau kalau return value-nya juga pasti
PLAINTEXT Snippetplaintext
1
number
1 baris•6 chars
UTF-8•Spaces: 4
. Pas kamu manggil
PLAINTEXT Snippetplaintext
1
getFirst(["Andi", "Budi"])
1 baris•26 chars
UTF-8•Spaces: 4
,
PLAINTEXT Snippetplaintext
1
T
1 baris•1 chars
UTF-8•Spaces: 4
jadi
PLAINTEXT Snippetplaintext
1
string
1 baris•6 chars
UTF-8•Spaces: 4
, dan return value-nya ikut jadi
PLAINTEXT Snippetplaintext
1
string
1 baris•6 chars
UTF-8•Spaces: 4
.
Ini bedanya generic sama
PLAINTEXT Snippetplaintext
1
any
1 baris•3 chars
UTF-8•Spaces: 4
.
PLAINTEXT Snippetplaintext
1
any
1 baris•3 chars
UTF-8•Spaces: 4
itu ngilangin informasi tipe sama sekali. Generic itu justru mempertahankan hubungan antara tipe input dan output, tapi tetep fleksibel buat dipake dengan tipe data apa aja.
Generic di Interface dan Type
Generic gak cuma bisa dipake di fungsi, tapi juga di interface atau type, biasanya buat bikin struktur data yang reusable.
di sini bisa dipake buat response API apa aja, tinggal ganti
PLAINTEXT Snippetplaintext
1
T
1 baris•1 chars
UTF-8•Spaces: 4
-nya sesuai bentuk data yang dikembaliin. Kamu gak perlu bikin interface terpisah kayak
PLAINTEXT Snippetplaintext
1
ApiResponseUser
1 baris•15 chars
UTF-8•Spaces: 4
dan
PLAINTEXT Snippetplaintext
1
ApiResponseProduk
1 baris•17 chars
UTF-8•Spaces: 4
yang isinya sebenernya mirip banget, cuma beda di bagian
PLAINTEXT Snippetplaintext
1
data
1 baris•4 chars
UTF-8•Spaces: 4
.
Ini yang bikin generic kepake banget di proyek nyata, apalagi kalau kamu kerja dengan banyak endpoint API yang punya struktur response yang mirip tapi isinya beda-beda.
extends, Ngasih Batasan ke Generic
Kadang kamu gak mau generic-nya terlalu bebas nerima tipe apa aja. Misalnya, kamu bikin fungsi yang butuh properti tertentu ada di objeknya, gak peduli bentuk lengkapnya kayak apa.
Kalau kamu gak nulis type argument sama sekali kayak di
PLAINTEXT Snippetplaintext
1
hasilDefault
1 baris•12 chars
UTF-8•Spaces: 4
, TypeScript bakal pake
PLAINTEXT Snippetplaintext
1
unknown
1 baris•7 chars
UTF-8•Spaces: 4
sebagai default. Tapi kalau kamu butuh tipe yang lebih spesifik, tinggal kasih di dalam
PLAINTEXT Snippetplaintext
1
<>
1 baris•2 chars
UTF-8•Spaces: 4
kayak di
PLAINTEXT Snippetplaintext
1
hasilProduk
1 baris•11 chars
UTF-8•Spaces: 4
. Ini berguna banget buat bikin generic yang tetep bisa dipake dengan gampang meski kamu belum tau mau isi apa dari awal.
Contoh Dunia Nyata, Generic Buat Fungsi Fetch API
Biar makin kebayang, coba lihat contoh generic buat fungsi fetch data dari API, kasus yang hampir pasti ketemu di proyek nyata.
index.tstypescript
1
asyncfunctionfetchData<T>(url:string):Promise<T>{
2
const response =awaitfetch(url);
3
return response.json();
4
}
5
6
interfaceUser{
7
id:number;
8
nama:string;
9
}
10
11
interfaceProduk{
12
id:number;
13
harga:number;
14
}
15
16
const user =awaitfetchData<User>("/api/user/1");
17
const produk =awaitfetchData<Produk>("/api/produk/1");
18
19
console.log(user.nama);// aman, TypeScript tau ini User
20
console.log(produk.harga);// aman, TypeScript tau ini Produk
20 baris•451 chars
UTF-8•Spaces: 4
Satu fungsi
PLAINTEXT Snippetplaintext
1
fetchData
1 baris•9 chars
UTF-8•Spaces: 4
bisa dipake buat ambil data apa aja, tinggal kasih tau tipe yang diharapkan lewat
PLAINTEXT Snippetplaintext
1
<User>
1 baris•6 chars
UTF-8•Spaces: 4
atau
PLAINTEXT Snippetplaintext
1
<Produk>
1 baris•8 chars
UTF-8•Spaces: 4
. Ini jauh lebih rapi dibanding bikin fungsi terpisah kayak
PLAINTEXT Snippetplaintext
1
fetchUser
1 baris•9 chars
UTF-8•Spaces: 4
dan
PLAINTEXT Snippetplaintext
1
fetchProduk
1 baris•11 chars
UTF-8•Spaces: 4
yang isinya sebenarnya sama persis, cuma beda tipe return-nya.
Kesimpulan
Generics itu sebenarnya bukan soal bikin kode kelihatan lebih canggih atau lebih rumit. Generics itu soal bikin kode reusable tanpa kehilangan informasi tipe, yang berarti kamu tetep dapet semua manfaat type safety meskipun fungsi atau struktur data yang kamu bikin dipake buat banyak tipe data yang berbeda-beda. Mulai dari generic function sederhana, generic interface,
PLAINTEXT Snippetplaintext
1
extends
1 baris•7 chars
UTF-8•Spaces: 4
buat ngasih batasan, sampai default type parameter, semuanya sebenarnya cuma alat buat satu tujuan, bikin kode kamu fleksibel tapi tetep aman.
Di artikel selanjutnya, yang juga jadi penutup Series 1, kita bakal bahas utility types yang paling sering dipake di proyek nyata, kayak
PLAINTEXT Snippetplaintext
1
Partial
1 baris•7 chars
UTF-8•Spaces: 4
,
PLAINTEXT Snippetplaintext
1
Pick
1 baris•4 chars
UTF-8•Spaces: 4
,
PLAINTEXT Snippetplaintext
1
Omit
1 baris•4 chars
UTF-8•Spaces: 4
, dan
PLAINTEXT Snippetplaintext
1
Record
1 baris•6 chars
UTF-8•Spaces: 4
, sebelum kita lanjut ke Series 2 yang bahas type level programming lebih dalam.
Software engineer dan konsultan sistem di SejatiDimedia. Berfokus pada perancangan arsitektur berkinerja tinggi, refactoring backend skala enterprise, hingga pengembangan aplikasi mobile, web modern dan integrasi AI.