[Medium] Generics
1. Apa itu generics?
Masalah apa yang diselesaikan generics di TypeScript?
Generics memungkinkan Anda menulis kode yang dapat digunakan ulang dan type-safe tanpa harus meng-hardcode satu tipe konkret.
Tanpa generics, Anda sering menduplikasi fungsi untuk setiap tipe. Dengan generics, satu implementasi bisa bekerja untuk banyak tipe sambil mempertahankan informasi tipe.
2. Fungsi generic (Generic Functions)
Sintaks dasar
function identity<T>(value: T): T {
return value;
}
const n = identity<number>(123);
const s = identity('hello'); // tipe disimpulkan sebagai string
Helper array generic
function firstItem<T>(items: T[]): T | undefined {
return items[0];
}
const firstNumber = firstItem([1, 2, 3]);
const firstString = firstItem(['a', 'b']);
3. Constraint generic (Generic Constraints)
Terkadang Anda memerlukan tipe generic dengan field yang diperlukan.
function getLength<T extends { length: number }>(value: T): number {
return value.length;
}
getLength('TypeScript');
getLength([1, 2, 3]);
// getLength(123); // Error: number tidak punya length
extends di sini berarti "harus memenuhi bentuk ini".
4. Parameter tipe ganda (Multiple Type Parameters)
function toPair<K, V>(key: K, value: V): [K, V] {
return [key, value];
}
const pair = toPair('id', 1001); // [string, number]
Ini umum di map, dictionary, dan utilitas transformasi data.
5. Interface dan type alias generic
Interface generic
interface ApiResponse<T> {
success: boolean;
data: T;
error?: string;
}
const userResponse: ApiResponse<{ id: number; name: string }> = {
success: true,
data: { id: 1, name: 'Pitt' },
};
Type alias generic
type Result<T> =
| { ok: true; value: T }
| { ok: false; message: string };
6. Class generic (Generic Classes)
class Queue<T> {
private items: T[] = [];
enqueue(item: T): void {
this.items.push(item);
}
dequeue(): T | undefined {
return this.items.shift();
}
}
const numberQueue = new Queue<number>();
numberQueue.enqueue(10);
7. Tipe generic default (Default Generic Types)
Anda bisa mendefinisikan tipe fallback.
type ApiResult<T = string> = {
data: T;
status: number;
};
const a: ApiResult = { data: 'ok', status: 200 };
const b: ApiResult<number> = { data: 1, status: 200 };
8. keyof dengan generics
function pick<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { id: 1, name: 'Alex' };
const name = pick(user, 'name'); // string
Pola ini adalah inti dari banyak utility type.
9. Kesalahan umum dan best practice
Kesalahan umum
- Menggunakan terlalu banyak parameter generic tanpa tujuan yang jelas
- Menamai semuanya
Tdi API yang kompleks - Kembali ke
anydaripada constraint yang tepat
Best practice
- Gunakan nama deskriptif untuk kasus kompleks (
TItem,TValue) - Tambahkan constraint di mana perilaku bergantung pada bentuk
- Utamakan inference dulu, argumen tipe eksplisit hanya saat diperlukan
- Jaga API generic tetap kecil dan fokus
10. Jawaban cepat wawancara
Q1: Apa manfaat terbesar dari generics?
Kode yang dapat digunakan ulang dengan keamanan tipe pada waktu kompilasi.
Q2: Apa arti T extends U?
T harus bisa di-assign ke U; ini adalah constraint generic.
Q3: Kapan harus menghindari generics?
Ketika abstraksi tidak meningkatkan kejelasan atau hanya mendukung satu tipe konkret.