TypeScript memakai try, catch, finally, dan throw dari JavaScript. Bagian yang khas TypeScript adalah variabel catch: dengan strict menyala, variabel itu bertipe unknown, jadi kamu memeriksa apa yang dilempar sebelum memakainya.
Sisi runtime-nya (cara stack dibongkar, tipe error bawaan apa saja yang ada) dibahas di try/catch JavaScript.
Kenapa Variabel catch Bertipe unknown
JavaScript bisa melempar apa saja: Error, string, angka, undefined, objek dari sebuah library. TypeScript tidak bisa tahu yang mana, jadi dengan strict (flag useUnknownInCatchVariables) variabelnya bertipe unknown dan kamu wajib mempersempitnya sebelum dipakai:
index.ts(5,34): error TS18046: 'e' is of type 'unknown'.
Tanpa strict, e bertipe any dan kode yang sama bisa dikompilasi, lalu bermasalah saat runtime kalau yang dilempar adalah string: e.message bernilai undefined, dan akses yang lebih dalam, seperti e.message.length, melempar TypeError. Kamu juga tidak bisa lolos dengan anotasi: catch (e: Error) menghasilkan error TS1196 (Catch clause variable type annotation must be 'any' or 'unknown' if specified).
Mempersempit Error
instanceof Error mencakup semua yang dibangun di atas Error, termasuk TypeError, SyntaxError, RangeError, dan subclass buatanmu sendiri. Untuk yang lainnya, ubah nilainya menjadi string. Helper kecil membuat tempat pemanggilan tetap singkat:
catch yang hanya menangani sebagian error sebaiknya melempar ulang sisanya: if (!(e instanceof ValidationError)) throw e;. Menelan error yang tidak dikenal menyembunyikan bug sungguhan.
Melempar Error
throw menerima ekspresi apa pun, dan TypeScript tidak membatasinya. Tetaplah melempar objek Error: objek ini membawa stack trace, dan setiap pemeriksaan instanceof Error di codebase bergantung padanya.
Fungsi yang selalu melempar error punya tipe kembalian never, yang dipakai TypeScript untuk mempersempit tipe setelah pemanggilan:
Sejak ES2022, Error menerima argumen kedua berisi cause, yang merangkai error tingkat rendah ke error yang kamu lempar: throw new Error("could not load settings", { cause: e }). Pemanggil bisa membaca err.cause (bertipe unknown).
Class Error Kustom
Subclass dari Error membuat pemanggil bisa membedakan kegagalan dengan instanceof dan membawa data tambahan. Atur name, karena nilai warisannya adalah "Error" dan nilai itu muncul di log serta di String(err):
Periksa class yang paling spesifik lebih dulu, karena NotFoundError juga merupakan HttpError. Modifier override di sini opsional, kecuali noImplicitOverride menyala.
Panduan lama menambahkan Object.setPrototypeOf(this, new.target.prototype) ke setiap constructor error. Itu dibutuhkan saat class dikompilasi menjadi fungsi ES5, di mana instanceof rusak untuk subclass Error. TypeScript 7 tidak lagi mendukung target: "es5" (ia melaporkan TS5108: Option 'target=ES5' has been removed), dan dengan ES2015 atau yang lebih baru, class ... extends Error bawaan berfungsi seperti di atas.
Pola Result
TypeScript tidak melacak error apa saja yang bisa dilempar sebuah fungsi, jadi tidak ada yang mengingatkan pemanggil untuk menanganinya. Untuk kegagalan yang memang diperkirakan (input tidak valid, data yang tidak ada), mengembalikan nilai yang menyatakan "sukses atau gagal" memasukkan error ke dalam sistem tipe:
Membaca r.value sebelum memeriksa r.ok adalah error kompilasi, dan memang itulah tujuannya. Pakai exception untuk hal yang tidak terduga (bug, koneksi yang putus) dan nilai Result untuk hasil yang harus diputuskan oleh pemanggil.
Error di Kode Async
Promise yang di-reject menjadi error yang dilempar di await, jadi try/catch di sekitar await bekerja dengan cara yang sama, dan variabelnya kembali bertipe unknown. Satu-satunya perbedaan adalah .catch() pada promise: parameter callback-nya bertipe any, bukan unknown, jadi beri anotasi sendiri (.catch((e: unknown) => ...)). Lihat async/await untuk contohnya.
Kesalahan Umum
- Membaca
e.messagetanpa mempersempit. Denganstrict, kodenya tidak bisa dikompilasi; tanpastrict, kodenya rusak saat yang dilempar bukanError. - Menangkap semuanya lalu lanjut berjalan. Tangani error yang kamu perkirakan dan lempar ulang sisanya.
- Lupa mengatur
namepada error kustom. Log lalu menyebut semuanya sebagaiError. - Melempar string.
throw "failed"tidak punya stack trace dan gagal dalam pemeriksaaninstanceof Error.
Pertanyaan yang sering diajukan
Apa tipe error di blok catch TypeScript?
unknown ketika strict menyala (flag useUnknownInCatchVariables), selain itu any. JavaScript bisa melempar nilai apa pun, bukan hanya objek Error, jadi TypeScript mewajibkanmu memeriksanya. Persempit dengan if (e instanceof Error) sebelum membaca e.message.
Apakah aku bisa memberi tipe Error pada variabel catch di TypeScript?
Tidak. catch (e: Error) menghasilkan error TS1196: Catch clause variable type annotation must be 'any' or 'unknown' if specified. Hanya unknown dan any yang diizinkan, karena tidak ada yang menjamin apa yang dilempar. Persempit di dalam bloknya saja.
Bagaimana cara melempar error di TypeScript?
Sama seperti di JavaScript: throw new Error("message"), atau instance dari subclass bawaan atau kustom seperti new RangeError(...). TypeScript membolehkanmu melempar nilai apa pun, tetapi melempar objek Error menjaga stack trace dan membuat pemeriksaan instanceof Error berfungsi.
Bagaimana cara membuat class error kustom di TypeScript?
Extend Error, panggil super(message, options), lalu atur name: class NotFoundError extends Error { name = "NotFoundError"; }. Field tambahan ditaruh di constructor. Dengan target apa pun yang didukung (ES2015 ke atas), instanceof NotFoundError berfungsi tanpa perbaikan prototype.
Apakah TypeScript punya checked exception atau klausa throws?
Tidak. Tipe sebuah fungsi tidak menyatakan apa pun tentang apa yang mungkin dilemparnya, dan compiler tidak pernah memeriksa bahwa error ditangani. Untuk error yang memang harus ditangani pemanggil, kembalikan sebagai nilai dengan tipe Result (discriminated union dari sukses dan gagal) supaya sistem tipe ikut memeriksanya.