Lewati ke konten utama
menjadi.dev
Chapter 18.3 JavaScript Menengah

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

Diagram

      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

typescript
// 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

fetchApi<T> menjaga tipe dari response JSON. extends object sebagai constraint memastikan T adalah object. Type guard isUser memvalidasi runtime shape.

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?