Pengenalan tipe generic pada Typescript
Generic merupakan salah satu fitur pada typescript. Generic memungkinkan developer melakukan abstraksi terhadap tipe data dalam typescript. Tipe data generic ditandai dengan penggunaan Angle Bracket (<>)
sebagai pembungkus dari suatu type.
type Generic<T> = T
Pengenalan
Konsep Don't Repeat Yourself (Dry) merupakan konsep yang penting dalam konteks penulisan kode yang dinamis dan reusable.
Dengan generic kita dapat membuat kode yang reusable pada function, class, atupun interface.
Tanpa disadari, kita mungkin sudah pernah mengimplementasikan generic pada kehidupan sehari-hari. Sebagai contoh mari lihat potongan kode berikut :
const [counter, setCounter] = useState<number>(0)
Kode diatas menginisialisasi state counter
dan setter setCounter
menggunakan useState
hook. Dengan memberikan tipe data number
secara eksplisit lewat generic.
Kebanyakan hook pada react secara default sudah menerapkan generic. Sehingga kita dapat mengetahui secara pasti tipe data variable
dari hook-hook tersebut.
Contoh kasus
Terkadang kita ingin membuat sebuah function yang menerima parameter dengan tipe data yang berbeda, akan tetapi memiliki logic yang sama. Seperti contoh berikut :
// Tipe parameter number
function foo(param: number): number {
// ...
return param
}
// Tipe parameter string
function foo(param: string): string {
// ...
return param
}
Dalam kode diatas, kita mendefinisikan function
yang sama untuk tipe data number
dan tipe data string
. Akan lebih baik jika kita mengabstraksi tipe data yang diterima dari function sehingga kita tidak perlu mengulang kode yang sama secara terus menerus. Dengan generic kita bisa melakukannya !
Membuat Tipe Generic
Untuk lebih memahami konsep dari generic, pertama mari kita ubah setiap tipe data function diatas menjadi any
. Tipe any
dalam typescript memungkinkan kita untuk melakukan assign terhadap semua type yang ada pada typescript.
function foo(param: any): any {
// ...
return param
}
Bagus, sekarang kita dapat melakukan assign terhadap semua tipe data. Namun apakah ada cara agar typescript dapat melakukan infer terhadap tipe data yang kita sediakan pada parameter ? Sehingga, tipe data apapun yang ada pada parameter akan digunakan juga sebagai Return Type
dari function tersebut. Disinilah fitur generic akan kita terapkan.
function foo<T>(param: T): T {
// ...
return param
}
Pada kode diatas kita membuat function foo
menjadi generic ditandai dengan penggunaan <T>
, dimana type T
adalah tipe data generic. Artinya, type T
akan tergantung dari type yang kita spesifikasikan. Seperti contoh berikut :
function foo<T>(param: T): T {
// ...
return param
}
const a = foo<number>(2)
a //number
const b = foo<string>('2')
b //string
Tentu saja jika generic yang kita spesifikasikan tidak sesuai dengan tipe dari param
, maka typescript akan memberikan error.
const a = foo<number>('2') // Error karena number is not assignable dengan string
const b = foo<string>(2) // Error karena string is not assignable dengan number
Pada function yang pertama, kita memberikan type number
sebagai generic dari function foo
. Sehingga tipe dari param dan tipe data yang di return oleh function akan menjadi number. Sebaliknya pada function kedua kita memberi type string
, sehingga tipe param dan Return type
function menjadi string.
Kamu bisa menganggap generic seperti function biasa, dapat menerima argumen (dalam hal diatas type argument
) dan menggunakan argumen tersebut didalamnya. Hanya saja argumen pada generic secara khusus hanya menerima type
saja.
Oke, sekarang kita punya function foo
yang memiliki Return type
sesuai dengan tipe yang kita spesifikasi tanpa harus melakukan duplikasi kode. Masalah kita sudah terselesaikan. Tetapi saya ingin menunjukkan satu hal yang menarik !
Mari coba hilangkan Type argument
saat kita memanggil function foo
dan lihat apa yang terjadi.
function foo<T>(param: T): T {
// ...
return param
}
const a = foo(2)
a // tipe data a menjadi 2
const b = foo('2')
b //tipe data b menjadi '2'
Tipe data dari variabel a
dan b
menjadi sama dengan argumen dari function foo
😮😮. Wow apa yang terjadi ?
Jadi ketika generic digunakan didalam function dan kita tidak memberikan type terhadap generic tersebut, maka typescript akan berusaha melakukan infering
kepada generic pada saat runtime. Pada kasus diatas, param
memiliki type T
, jadi typescript akan menyimpulkan bahwa type yang dimiliki oleh param
adalah sama dengan type yang dimiliki oleh T
. Begitupula dengan Return type
dari function tersebut. Sehingga tipe yang kita berikan pada setiap instansiasi function menjadi dinamis dan berbeda-beda sesuai dengan parameter yang kita berikan.
Satu hal lagi, pada contoh diatas kita menggunakan const
pada saat mendefinisikan variabel a
dan b
. Karena nilai pada const
adalah constant
, maka typescript akan cukup cerdas saat melakukan infering
. Sehingga tipe data yang didapatkan bukanlah number
atau string
, melainkan 2
atau '2'
. Sebaliknya, jika kita menggunakan let
, maka tipe yang kita dapatkan adalah string
atau number
, karena variabel tersebut mungkin saja berubah.
Penutup
That's it ! Ada banyak sekali hal lain yang bisa kita lakukan terhadap generic, seperti melakukan Conditional Type
, Mapped Type
, dll. Sayangnya kita tidak akan membahasnya pada artikel kali ini (mungkin di artikel selanjutnya). Terimakasih karena sudah membaca sampai akhir. Akhir kata saya ucapkan Terima kasih :).