void dan never pada Fungsi
Bedakan fungsi tanpa return (void) dan fungsi yang tidak pernah selesai (never).
Kenapa Ada Dua Tipe untuk "Tidak Ada"?
Bayangkan kamu memesan ojek online. Ada dua skenario aneh: pertama, driver datang, mengantar kamu, lalu pergi tanpa bilang apa-apa. Itu void: pekerjaan selesai, tapi tidak ada "hasil" yang dibawa pulang. Kedua, driver tidak pernah sampai karena motornya mogok di tengah jalan dan ia menelepon membatalkan. Itu never: pekerjaan tidak pernah selesai secara normal. TypeScript memisahkan dua konsep ini karena konsekuensi kodenya beda jauh.
void dalam Praktik Sehari-hari
Fungsi void adalah fungsi yang selesai tanpa mengembalikan nilai yang bermakna. Kamu menemukannya di mana-mana: event handler, callback forEach, middleware, fungsi logging.
function catatAktivitas(aksi: string): void {
console.log(`[${new Date().toISOString()}] ${aksi}`);
}
["login", "logout"].forEach((aksi) => catatAktivitas(aksi));void bukan berarti "dilarang return". Kamu boleh menulis return; kosong untuk keluar lebih awal, tapi tidak boleh me-return sebuah nilai. Ini contoh yang ditolak compiler:
function sapa(nama: string): void {
return `Halo, ${nama}`;
// Error: Type 'string' is not assignable to type 'void'.
}Pesan errornya jelas: kamu berjanji tidak mengembalikan apa-apa, lalu malah mengembalikan string. Perbaikannya: hapus anotasi void bila memang butuh return, atau hapus nilai return-nya bila memang tidak butuh.
Satu jebakan klasik: mencoba memakai hasil fungsi void seolah ada nilainya.
const hasil = catatAktivitas("login");
console.log(hasil.toUpperCase());
// Error: Property 'toUpperCase' does not exist on type 'void'.Ini justru fitur, bukan bug. Compiler menangkap logika yang salah: kamu mengira ada string yang kembali, padahal tidak.
never: Fungsi yang Tidak Pernah Kembali Normal
Fungsi never tidak pernah mencapai baris akhir secara normal. Ia hanya punya dua jalan keluar: melempar error, atau loop selamanya. Analogi gampangnya: void itu tamu yang pulang tanpa bawa oleh-oleh, never itu tamu yang tidak pernah pulang.
function gagalFatal(pesan: string): never {
throw new Error(pesan);
}
function tungguSelamanya(): never {
while (true) {
// polling tanpa henti, mis. worker
}
}Kalau kamu mendeklarasikan never tapi badannya bisa selesai normal, compiler protes:
function puraPuraFatal(): never {
console.log("selesai");
// Error: A function whose declared type is neither 'void' nor 'any'
// must return a value.
}Kapan Bedanya Benar-benar Penting
Skenario nyata: kamu punya union status dan sebuah switch yang harus menangani semuanya. Trik never membuat compiler menjadi penjaga yang memastikan tidak ada kasus yang terlewat.
type Status = "antri" | "proses" | "selesai";
function labelStatus(s: Status): string {
switch (s) {
case "antri": return "Dalam antrian";
case "proses": return "Sedang diproses";
case "selesai": return "Selesai";
default:
const takTerduga: never = s;
throw new Error(`Status tak dikenal: ${takTerduga}`);
}
}Di cabang default, tipe s sudah menyempit menjadi never karena semua kemungkinan habis. Kalau suatu hari ada yang menambah "batal" ke union Status tapi lupa menambah case, baris const takTerduga: never = s; langsung error saat compile. Tanpa trik ini, bug-nya baru ketahuan saat user mengklik di production. Inilah kenapa never ada: mengubah bug runtime menjadi error compile time.
Pola lain yang umum: helper validasi yang selalu throw, dipakai sebagai expression.
function wajibAda<T>(nilai: T | undefined, nama: string): T {
if (nilai === undefined) {
gagalFatal(`${nama} wajib diisi`);
}
return nilai; // compiler tahu baris ini hanya tercapai bila nilai ada
}Karena gagalFatal bertipe never, compiler paham bahwa setelah pemanggilannya, kode di bawah hanya jalan bila kondisi tidak terpenuhi. Tanpa anotasi never, compiler akan mengira eksekusi bisa lanjut dan memaksa kamu menulis handling tambahan yang tidak perlu.
Catatan teknis:
neveradalah satu-satunya tipe yang assignable ke semua tipe, tapi tidak ada tipe (selainneversendiri) yang assignable kenever. Itu sebabnya trik exhaustive check di atas bekerja: hanya nilai yang "tidak mungkin ada" yang bisa masuk ke variabelnever.
Tantangan
Validasi yang tidak pernah lolos diam-diam
Buat fungsi pastikanPositif(n: number): void yang melempar Error bila n <= 0 (tidak return apa-apa bila valid), dan fungsi gagalFatal(pesan: string): never yang selalu throw. Panggil keduanya dengan benar.
function pastikanPositif(n: number): void {
// lempar bila n <= 0
}
function gagalFatal(pesan: string): never {
// selalu throw
}
pastikanPositif(5);
console.log("lolos validasi");Kuis Bab
Uji pemahamanmu: Fungsi Lebih Dalam
Jawab 5 soal berikut, lalu tekan "Periksa Jawaban".
1.Apa kegunaan literal type seperti "kiri" | "kanan"?
2.Kenapa komunitas modern lebih memilih literal union dibanding enum?
3.Apa itu function overload?
4.Apa beda parameter opsional (?) dan parameter default (=)?
5.Kapan memakai never sebagai return type?