TypeScript - Generic Classes

Hai, para bintang pemrograman masa depan! Hari ini, kita akan melihat dunia menarik TypeScript Generic Classes. Jangan khawatir jika Anda baru saja memulai pemrograman; saya akan memandu Anda melalui perjalanan ini langkah demi langkah, seperti yang saya lakukan untuk ribuan murid selama tahun-tahun mengajar. Jadi, ambil minuman favorit Anda, duduk nyaman, dan mari kita mulai petualangan ini bersama!

TypeScript - Generic Classes

Generic Classes

Apa Itu Generic Classes?

Bayangkan Anda di toko es krim, tapi bukan untuk memilih rasa, melainkan jenis data. Itu esensi generic classes! Mereka memungkinkan kita untuk menciptakan komponen fleksibel dan dapat digunakan kembali yang dapat bekerja dengan jenis data yang berbeda tanpa mengorbankan keamanan tipe.

mari mulai dengan contoh sederhana:

class Box<T> {
private content: T;

constructor(value: T) {
this.content = value;
}

getValue(): T {
return this.content;
}
}

Dalam contoh ini, Box adalah kelas generic. <T> adalah seperti placeholder untuk jenis yang akan kita tentukan kemudian. Itu seperti mengatakan ke toko es krim, "Saya akan memutuskan rasa saat saya memesan!"

mari kitauraikan ini:

  • class Box<T>: Ini mendeklarasikan kelas generic bernama Box dengan parameter jenis T.
  • private content: T: Kita mengatakan bahwa content akan berjenis T, apa pun T yang menjadi.
  • constructor(value: T): Konstruktor menerima nilai jenis T.
  • getValue(): T: Metode ini mengembalikan nilai jenis T.

Sekarang, mari kita lihat bagaimana kita dapat menggunakan kelas ini:

let numberBox = new Box<number>(42);
console.log(numberBox.getValue()); // Output: 42

let stringBox = new Box<string>("Hello, TypeScript!");
console.log(stringBox.getValue()); // Output: Hello, TypeScript!

Apakah itu menarik? Kita telah menggunakan kelas Box yang sama untuk menyimpan baik number dan string. Itu seperti memiliki kotak ajaib yang dapat menahan apa pun yang Anda masukkan ke dalamnya, tetapi tetap ingat jenis apa yang dimiliki!

Beberapa Parameter Jenis

kadang-kadang, satu parameter jenis saja tidak cukup. mari buat contoh yang lebih kompleks dengan beberapa parameter jenis:

class Pair<T, U> {
private first: T;
private second: U;

constructor(first: T, second: U) {
this.first = first;
this.second = second;
}

getFirst(): T {
return this.first;
}

getSecond(): U {
return this.second;
}
}

Kelas Pair ini dapat menahan dua nilai jenis yang mungkin berbeda. Itu seperti memiliki es krim berdua di mana setiap scoop dapat memiliki rasa yang berbeda!

mari gunakan kelas Pair kami:

let pair = new Pair<string, number>("Age", 30);
console.log(pair.getFirst());  // Output: Age
console.log(pair.getSecond()); // Output: 30

Batasan Generic

kadang-kadang, kita ingin membatasi jenis apa saja yang dapat digunakan dengan kelas generic kita. Kita dapat melakukan ini menggunakan batasan. Itu seperti mengatakan, "Anda dapat memesan es krim rasa apa pun, selama itu tidak terlalu pedas!"

interface Lengthwise {
length: number;
}

class LengthChecker<T extends Lengthwise> {
checkLength(obj: T): string {
return `Panjangnya adalah: ${obj.length}`;
}
}

Dalam contoh ini, T extends Lengthwise berarti T harus jenis yang memiliki properti length. mari gunakan ini:

let stringChecker = new LengthChecker<string>();
console.log(stringChecker.checkLength("Hello")); // Output: Panjangnya adalah: 5

let arrayChecker = new LengthChecker<number[]>();
console.log(arrayChecker.checkLength([1, 2, 3])); // Output: Panjangnya adalah: 3

// Ini akan menyebabkan kesalahan:
// let numberChecker = new LengthChecker<number>();
// Type 'number' does not satisfy the constraint 'Lengthwise'.

Implementasi Interface Generic dengan Kelas Generic

Sekarang, mari kita tingkatkan keterampilan kita dengan mengimplementasikan interface generic dengan kelas generic. Itu seperti membuat resep (interface) untuk jenis es krim yang berbeda (kelas)!

Pertama, mari kita tentukan interface generic:

interface Repository<T> {
getById(id: number): T;
save(item: T): void;
}

Interface Repository ini mendefinisikan kontrak untuk kelas yang akan mengelola penyimpanan dan pengambilan data. Sekarang, mari kita implementasikan interface ini dengan kelas generic:

class GenericRepository<T> implements Repository<T> {
private items: T[] = [];

getById(id: number): T {
return this.items[id];
}

save(item: T): void {
this.items.push(item);
}
}

Kelas GenericRepository kami mengimplementasikan interface Repository. Itu dapat bekerja dengan jenis apa pun T. mari gunakan ini:

interface User {
name: string;
age: number;
}

let userRepo = new GenericRepository<User>();

userRepo.save({ name: "Alice", age: 30 });
userRepo.save({ name: "Bob", age: 25 });

console.log(userRepo.getById(0)); // Output: { name: "Alice", age: 30 }
console.log(userRepo.getById(1)); // Output: { name: "Bob", age: 25 }

Dalam contoh ini, kita telah menciptakan repositori untuk objek User. Tetapi keindahan implementasi generic kita adalah kita dapat dengan mudah menciptakan repositori untuk jenis lainnya!

Tabel Metode

Berikut adalah tabel praktis yang menggabungkan metode yang kita pelajari:

Metode Deskripsi Contoh
constructor(value: T) Membuat instance baru dari kelas generic new Box<number>(42)
getValue(): T Mengembalikan nilai yang disimpan dalam kelas generic numberBox.getValue()
getFirst(): T Mengembalikan nilai pertama dalam pasangan pair.getFirst()
getSecond(): U Mengembalikan nilai kedua dalam pasangan pair.getSecond()
checkLength(obj: T): string Memeriksa panjang objek (dengan batasan) stringChecker.checkLength("Hello")
getById(id: number): T Mengambil item dari repositori berdasarkan ID userRepo.getById(0)
save(item: T): void Menyimpan item ke repositori userRepo.save({ name: "Alice", age: 30 })

Dan itu saja, teman-teman! Kita telah melakukan perjalanan melalui negeri TypeScript Generic Classes, dari kotak sederhana ke repositori kompleks. Ingat, latihan membuat sempurna, jadi jangan khawatir untuk mencoba konsep ini. Siapa tahu? Anda mungkin menciptakan hal yang besar dalam pemrograman! Sampaijumpa lagi, selamat coding!

Credits: Image by storyset