Functions, Generics, dan Type Narrowing
Tingkatkan fungsi JavaScript dengan type safety dan reusable patterns
Tujuan Pembelajaran
- Bisa mengetik fungsi dengan parameter dan return type
- Mengerti dan menggunakan generics
- Menguasai type narrowing dan type guards
Analogi
Functions:
├── Parameter types
├── Return type
├── Optional & default params
└── Overloads
Generics:
└── function identity<T>(arg: T): T
Functions + Generics + Type Narrowing = kode yang fleksibel tapi tetap type-safe
Penjelasan Konsep
Setelah menguasai tipe dasar, saatnya belajar mengetik fungsi dan pattern advanced yang membuat TypeScript sangat powerful.
Typing Functions
TypeScript memungkinkan kamu menentukan tipe parameter dan return value:
function tambah(a: number,
B: number): number {
return a + b;
}
// Optional parameter
function greet(nama: string, greeting?: string): string {
return `${greeting ??
'Halo'}, ${nama}!`;
}
// Default parameter
function greet(nama: string, greeting: string = 'Halo'): string {
return `${greeting}, ${nama}!`;
}
Function Type / Callback
Definisikan tipe fungsi sebagai variabel:
type Calculator = (a: number, b: number) => number;
const tambah: Calculator = (a, b) => a + b;
const kali: Calculator = (a,
B) => a * b;
Generics: Fungsi yang Bekerja untuk Tipe Apa Pun
Generics memungkinkan fungsi/class/interface bekerja dengan berbagai tipe tanpa kehilangan type information:
// Tanpa generic — kehilangan tipe
function identity(arg: any): any {
return arg;
}
const result = identity(5); // result bertipe 'any' 😞
// Dengan generic — tipe terjaga
function identity<T>(arg: T): T {
return arg;
}
const result = identity(5); // result bertipe 'number' ✓
Generics adalah salah satu fitur paling powerful TypeScript.
Tanpa generics, kamu harus pilih: fleksibel (any) atau type-safe (tipe spesifik).
Dengan generics, kamu dapat keduanya.
Type Narrowing: Mengpersempit Tipe
Type narrowing adalah teknik mempersempit union type ke tipe yang lebih spesifik:
function process(value: string | number) {
if (typeof value === 'string') {
// Di sini, value bertipe 'string'
return value.toUpperCase();
} else {
// Di sini,
Value bertipe 'number'
return value.toFixed(2);
}
}
Type Guards
Type guard adalah fungsi yang memeriksa tipe runtime dan memberi tahu TypeScript:
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function process(value: unknown) {
if (isString(value)) {
// value adalah string di sini
return value.toUpperCase();
}
} Contoh Kode
// Generic function untuk API fetch
async function fetchApi<T>(url: string): Promise<T> {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json() as Promise<T>;
}
// Penggunaan — tipe terjaga!
interface User { id: number; nama: string; }
interface Post { id: number; title: string; }
const user = await fetchApi<User>('/api/users/1');
// user bertipe User — autocomplete id, nama tersedia
const posts = await fetchApi<Post[]>('/api/posts');
// posts bertipe Post[] — autocomplete map, filter, dll
// Generic + Constraints
function merge<T extends object, U extends object>(a: T, b: U): T & U {
return { ...a, ...b };
}
const userConfig = merge(
{ nama: 'Budi' },
{ theme: 'dark' }
);
// userConfig: { nama: string; theme: string }
// Type guard untuk validasi
function isUser(obj: unknown): obj is User {
return (
typeof obj === 'object' &&
obj !== null &&
'id' in obj &&
'nama' in obj
);
}
const data = JSON.parse('{}');
if (isUser(data)) {
console.log(data.nama); // Type-safe!
}Penjelasan Kode
Prompt AI
Buat generic function filterByProperty<T> yang menerima array of T, key, dan value — mengembalikan elemen yang property-nya cocok. Gunakan keyof T.
Pertanyaan Reflektif
Tanpa generics, bagaimana kamu menulis fetchApi? Bandingkan dengan versi generic — apa bedanya dari sisi developer experience?