Type Guard
Fungsi predicate dengan 'is' untuk narrowing custom yang bisa dipakai ulang.
Batas typeof dan in
typeof hanya bisa membedakan primitif. in butuh properti pembeda yang unik. Bagaimana kalau logikanya lebih kompleks, misalnya "apakah object ini ikan" berdasarkan bentuk siripnya? Di sinilah type guard.
Predicate dengan is
interface Ikan { berenang: () => void; }
interface Burung { terbang: () => void; }
function adalahIkan(hewan: Ikan | Burung): hewan is Ikan {
return (hewan as Ikan).berenang !== undefined;
}
function gerak(hewan: Ikan | Burung) {
if (adalahIkan(hewan)) {
hewan.berenang(); // hewan: Ikan
} else {
hewan.terbang(); // hewan: Burung
}
}Return type hewan is Ikan adalah type predicate. Artinya: "kalau fungsi ini return true, anggap argumennya bertipe Ikan". Compiler lalu menerapkan narrowing seperti typeof biasa.
Guard untuk Validasi Data
Penggunaan paling nyata: memvalidasi data tak dikenal dari API atau JSON:
function adalahPengguna(x: unknown): x is { nama: string } {
return (
typeof x === "object" &&
x !== null &&
"nama" in x &&
typeof (x as Record<string, unknown>).nama === "string"
);
}
const data: unknown = JSON.parse(responsApi);
if (adalahPengguna(data)) {
console.log(data.nama.toUpperCase()); // aman
}Tanpa guard, data bertipe unknown dan tidak bisa diapa-apakan. Guard mengubah "data misterius" jadi "data terverifikasi".
Guard Bawaan: Array.isArray
Beberapa fungsi JavaScript sudah menjadi type guard resmi:
function proses(x: string | string[]) {
if (Array.isArray(x)) {
console.log(x.length); // x: string[]
} else {
console.log(x.toUpperCase()); // x: string
}
}Array.isArray dideklarasikan dengan return type arg is any[], jadi narrowing otomatis.
Catatan teknis: Type predicate adalah janji yang dipercaya compiler tanpa verifikasi. Kalau
adalahIkanreturn true untuk burung, tidak ada yang protes dan bug lolos diam-diam. Tulis logika guard sejujur mungkin dan unit test untuk guard yang kompleks. Predicate yang berbohong lebih berbahaya daripada tidak ada guard sama sekali.