uniontipe-datanarrowingMenengah3 mnt baca

Union Type

Satu nilai boleh beberapa tipe: union dengan | dan cara menyempitkannya.

Analogi: "Boleh yang Ini atau Itu"

Mesin fotokopi menerima koin ATAU uang kertas. Kasir menerima tunai ATAU QRIS. Union type (|) adalah cara TypeScript bilang "nilai ini boleh bertipe A atau bertipe B".

Kenapa Union Ada?

Data nyata jarang satu tipe melulu. ID user bisa string ("USR-1") dari database baru atau number (42) dari sistem lama. Response API bisa berisi data ATAU null saat tidak ketemu. Tanpa union, kamu terpaksa pakai any dan kehilangan semua perlindungan compiler.

typescript
let id: string | number;
id = "USR-1"; // OK
id = 42;      // OK
id = true;
// Error: Type 'boolean' is not assignable to type 'string | number'.

Hanya Boleh Operasi yang Aman untuk Semua

Selama tipenya masih union, compiler hanya mengizinkan operasi yang valid untuk SEMUA anggotanya:

typescript
function cetak(id: string | number) {
  console.log(id.toUpperCase());
  // Error: Property 'toUpperCase' does not exist on type 'number'.
}

Ini bukan compiler cerewet, ini compiler melindungimu: kalau id ternyata number saat runtime, .toUpperCase() akan crash. Solusinya adalah narrowing, persempit tipenya dulu dengan typeof:

typescript
function cetak(id: string | number) {
  if (typeof id === "string") {
    console.log(id.toUpperCase()); // di sini id: string, aman
  } else {
    console.log(id.toFixed(2));    // di sini id: number, aman
  }
}

Kapan Dipakai di Project Nyata

  • Parameter fleksibel: fungsi format(input: string | string[]) yang menerima satu nilai atau banyak.
  • Data opsional: User | null untuk hasil pencarian yang mungkin tidak ketemu, string | undefined untuk field form yang belum diisi.
  • Event dan state: status pemuatan "idle" | "loading" | "error" (digabung literal type), hasil operasi yang bisa sukses atau gagal.

Pola T | null dan T | undefined adalah cara idiomatis menangani "data mungkin tidak ada" di strict mode, jauh lebih aman daripada membiarkan null menyelinap tanpa anotasi.

Catatan teknis: Union dari object yang punya properti pembeda (kind: "a" | "b") disebut discriminated union dan dibahas tuntas di modul narrowing-discriminated-union. Itu pola andalan untuk state machine dan response API yang bercabang.

Contoh Nyata: Fungsi yang Bisa Gagal

typescript
interface User { nama: string; }

function cariUser(id: string): User | null {
  return id === "U1" ? { nama: "Budi" } : null;
}

const u = cariUser("U9");
console.log(u.nama);
// Error: 'u' is possibly 'null'.

if (u !== null) {
  console.log(u.nama); // OK, di sini u: User
}

Pola User | null memaksa pemanggil menangani kasus "tidak ketemu" secara eksplisit. Bandingkan dengan JavaScript murni: null menyelinap diam-diam lalu meledak sebagai TypeError jauh dari sumber masalahnya.

Tantangan

Format nilai fleksibel

Buat fungsi formatNilai(v: string | number): string yang mengembalikan string uppercase bila input string, atau string dengan 2 desimal bila input number. Gunakan narrowing typeof agar tidak ada error compiler.

typescript
function formatNilai(v: string | number): string {
  // narrowing di sini
}

console.log(formatNilai("halo")); // "HALO"
console.log(formatNilai(3.14159)); // "3.14"