# Mengapa unknown Adalah Pilihan yang Lebih Aman Daripada any di Blok catch TypeScript

Saat menangani error di TypeScript, kita sering kali menulis blok `try...catch` secara otomatis. Secara default, variabel error dalam blok `catch` memiliki tipe `any`, yang tampaknya memudahkan kita. Namun, kemudahan ini datang dengan risiko tersembunyi. Mengganti `any` dengan `unknown` adalah langkah kecil yang secara signifikan meningkatkan keamanan dan ketahanan kode Anda.

Mari kita bahas mengapa `unknown` adalah praktik terbaik yang seharusnya Anda adopsi.

---

### Masalah dengan `any`: Gerbang Menuju Runtime Error 💥

Tipe `any` pada dasarnya adalah cara untuk memberitahu TypeScript agar "mematikan" sistem pengecekan tipenya. Saat sebuah variabel bertipe `any`, Anda bisa melakukan apa saja padanya tanpa ada protes dari *compiler*. Anda bisa memanggilnya sebagai fungsi, mengakses properti apa pun, atau mengoperasikannya dengan nilai lain.

Masalahnya adalah, **tidak ada jaminan** bahwa objek yang ditangkap (`err`) benar-benar memiliki properti yang Anda harapkan. Di JavaScript (dan TypeScript), Anda bisa `throw` apa saja—bukan hanya instance `Error`.

Perhatikan contoh berbahaya ini:

TypeScript

```typescript
try {
  // Bayangkan sebuah fungsi atau API melempar string, bukan objek Error
  throw "Terjadi kesalahan jaringan!";
} catch (err: any) { // ❌ Menggunakan 'any'
  // Compiler tidak akan protes dengan baris ini
  console.error(err.message); // 💥 RUNTIME ERROR: Cannot read properties of undefined (reading 'message')
}
```

Kode di atas akan lolos saat kompilasi, tetapi akan **crash saat runtime**. Ini terjadi karena kita mencoba mengakses `err.message`, padahal `err` adalah sebuah *string* yang tidak memiliki properti `.message`. Inilah kelemahan utama `any`: ia menciptakan ilusi keamanan saat development yang bisa hancur saat produksi.

---

### Solusi Elegan: `unknown` untuk Keamanan Tipe 🛡️

Tipe `unknown` adalah saudara kembar `any` yang lebih aman dan bertanggung jawab. Seperti `any`, `unknown` bisa menampung nilai apa pun. Namun, perbedaannya sangat krusial: **TypeScript tidak akan membiarkan Anda melakukan operasi apa pun pada variabel bertipe** `unknown` sampai Anda membuktikan tipenya terlebih dahulu.

Proses pembuktian tipe ini disebut *type narrowing* atau penyempitan tipe.

Sekarang, mari kita perbaiki contoh sebelumnya menggunakan `unknown` berdasarkan kode yang Anda berikan:

TypeScript

```typescript
} catch (err: unknown) { // ✅ Menggunakan 'unknown'
    let errorMessage = 'Terjadi kesalahan pada server.';

    // 💡 Lakukan pengecekan tipe sebelum menggunakan 'err'
    if (err instanceof Error) {
      // Di dalam blok ini, TypeScript tahu bahwa 'err' adalah sebuah Error.
      // Aman untuk mengakses properti .message
      errorMessage = err.message;
    } else if (typeof err === 'string') {
      // Menangani kasus jika yang di-throw adalah string
      errorMessage = err;
    }

    console.error('Download ERROR:', err);
    // await sendTelegramError(c.get('username'), import.meta.url, err);

    // Kembalikan pesan error yang sudah aman dan terverifikasi
    return c.json({ error: errorMessage }, 500);
}
```

Dalam versi ini:

1. **Aman Secara Default:** Kita tidak bisa langsung mengakses `err.message`. Jika kita mencoba, TypeScript akan memberikan error saat kompilasi, mencegah *bug* sampai ke produksi.
    
2. **Penanganan Eksplisit:** Kode ini memaksa kita untuk berpikir dan menangani berbagai kemungkinan tipe error. Kita secara eksplisit memeriksa apakah `err` adalah instance dari `Error`. Kita bahkan bisa menambahkan pengecekan lain, seperti untuk `string` atau objek dengan struktur tertentu.
    
3. **Kode Defensif:** Pendekatan ini membuat kode kita lebih tangguh. Ia siap menghadapi berbagai jenis nilai yang mungkin dilempar (`throw`), bukan hanya objek `Error` standar.
    

---

### Cara Mengaktifkan Secara Default di `tsconfig.json`

Untuk memastikan Anda dan tim selalu menggunakan `unknown` di blok `catch`, TypeScript menyediakan opsi konfigurasi di `tsconfig.json`. Cukup tambahkan `useUnknownInCatchVariables` dan set ke `true`.

JSON

```typescript
{
  "compilerOptions": {
    // ... opsi lainnya
    "useUnknownInCatchVariables": true
  }
}
```

Dengan mengaktifkan ini, semua variabel `catch` tanpa anotasi tipe akan otomatis dianggap `unknown`, bukan `any`, sehingga mendorong praktik pengkodean yang lebih aman di seluruh proyek Anda.

### Kesimpulan

Mengganti `any` dengan `unknown` di blok `catch` lebih dari sekadar preferensi gaya; ini adalah tentang menulis kode yang lebih aman, lebih prediktif, dan lebih mudah dirawat. Ini adalah perubahan kecil yang mencerminkan pemahaman mendalam tentang prinsip-prinsip keamanan tipe yang menjadi inti dari TypeScript.

**Singkatnya,** `unknown` memaksa Anda untuk mengonfirmasi, sedangkan `any` membiarkan Anda berasumsi. Dalam dunia pengembangan perangkat lunak, konfirmasi selalu lebih baik daripada asumsi.
