Menu

Switch Case di TypeScript: Narrowing dan Exhaustive Check

Pernyataan switch di TypeScript: sintaks, bagaimana setiap case mempersempit tipe union, switch yang exhaustive sehingga gagal kompilasi kalau ada case yang terlewat, pola switch (true), fallthrough, dan scope blok.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Pernyataan switch di TypeScript adalah switch milik JavaScript dengan pengecekan tipe. Ia membandingkan sebuah nilai dengan setiap case memakai ===, menjalankan cabang yang cocok, dan berhenti di break atau return. TypeScript mempersempit nilai yang di-switch di dalam setiap case dan bisa mengecek bahwa setiap nilai yang mungkin sudah ditangani.

Label yang ditumpuk (case "sat": case "sun":) berbagi satu cabang. return mengakhiri fungsi, jadi tidak perlu break setelahnya.

Sintaks

switch (expression) {
    case value1:
        // runs when expression === value1
        break;
    case value2:
    case value3:
        // runs for value2 or value3
        break;
    default:
        // runs when nothing else matched
}
  • Pencocokan memakai kesamaan ketat, ===: case 1 tidak cocok dengan string "1".
  • Tanpa break, return atau throw, eksekusi berlanjut ke case berikutnya (fallthrough).
  • default bersifat opsional dan boleh ditaruh di mana saja, walaupun lazimnya di akhir.
  • Nilai case yang bisa dibuktikan TypeScript tidak pernah cocok adalah error TS2678. Untuk parameter bertipe "a" | "b", case "c": melaporkan Type '"c"' is not comparable to type '"a" | "b"'., sehingga salah ketik di label case ketahuan.

Narrowing di Dalam Setiap Case

Di setiap case, TypeScript tahu nilai mana yang cocok dan mempersempit tipenya. Ini paling berguna dengan discriminated union: lakukan switch pada property tag yang sama-sama dimiliki, dan setiap case melihat varian yang cocok beserta property miliknya sendiri.

shape.radius hanya lolos kompilasi di case "circle". Di luar case itu, shape bisa saja persegi panjang, yang tidak punya radius. Tidak ada default, dan fungsinya tetap lolos pengecekan tipe sebagai fungsi yang mengembalikan number, karena TypeScript melihat bahwa ketiga case sudah mencakup setiap kind. Pola lain yang dibangun di atas ini ada di halaman discriminated unions.

Exhaustive Switch dengan never

Fungsi di atas berhenti lolos kompilasi kalau bentuk keempat ditambahkan tanpa case (TS2366, return yang hilang). Itu hanya berhasil kalau fungsinya mengembalikan nilai. Untuk jaminan yang juga berlaku di kode void dan memberi pesan yang lebih jelas, tambahkan default yang meng-assign nilainya ke never:

index.ts(14,19): error TS2322: Type '{ kind: "triangle"; base: number; height: number; }' is not assignable to type 'never'.

Setelah case-case yang ditangani, satu-satunya tipe yang tersisa untuk shape adalah varian segitiga, dan varian itu tidak bisa di-assign ke never. Error-nya menyebut persis apa yang terlewat. Tambahkan case "triangle": return (shape.base * shape.height) / 2; dan default melihat never, sehingga bloknya lolos kompilasi dan mencetak 9. throw tetap menjaga dari data yang buruk saat runtime, seperti kind dari JSON yang tidak diantisipasi oleh tipenya.

Banyak codebase membungkus pengecekan ini dalam sebuah helper:

Teknik yang sama berlaku untuk enum: lakukan switch pada nilai enum dan kirim nilainya ke assertNever di default.

switch (true) untuk Rentang dan Kondisi

switch membandingkan nilai, jadi rentang butuh trik: lakukan switch pada true dan tulis kondisi di setiap case. Sejak TypeScript 5.3, kondisi-kondisi itu mempersempit tipe seperti pernyataan if.

Case diuji secara berurutan, jadi taruh yang paling spesifik lebih dulu. Apakah cara ini lebih enak dibaca daripada if / else if adalah soal selera; perilakunya sama.

Fallthrough dan break

Case yang punya kode tetapi tanpa break, return atau throw akan berlanjut ke case berikutnya. Itu hampir selalu bug. Opsi compiler noFallthroughCasesInSwitch (bukan bagian dari strict) mengubahnya menjadi error TS7029, Fallthrough case in switch., sambil tetap mengizinkan label kosong yang ditumpuk.

Fallthrough yang disengaja seperti ini memang berfungsi, tetapi kalau noFallthroughCasesInSwitch aktif, kodenya harus ditulis ulang, misalnya dengan pengecekan if yang terpisah. Biasanya cara itu memang lebih jelas.

Variabel di Dalam Case

Seluruh isi switch adalah satu blok, jadi const yang dideklarasikan di satu case terlihat di case lain (dan mendeklarasikannya ulang adalah error). Bungkus sebuah case dengan kurung kurawal supaya ia punya scope sendiri:

Tanpa kurung kurawal, const unit yang kedua adalah error kompilasi TS2451, Cannot redeclare block-scoped variable 'unit'.

switch vs Lookup Object

Kalau setiap case hanya memetakan satu nilai ke nilai lain, object bertipe Record lebih ringkas, dan TypeScript mengecek bahwa setiap key ada:

Melewatkan sebuah key adalah error kompilasi, yang memberi kelengkapan yang sama seperti pengecekan never. Pakai switch untuk case yang menjalankan logika berbeda, mempersempit varian union, atau melakukan return lebih awal.

Pertanyaan yang sering diajukan

Bagaimana cara menulis pernyataan switch di TypeScript?

Persis seperti di JavaScript: switch (value) { case "a": ...; break; default: ... }. Case dibandingkan dengan ===. TypeScript menambahkan pengecekan: nilai case yang tidak mungkin cocok dengan tipe yang di-switch adalah error (TS2678), dan di dalam setiap case variabel yang di-switch dipersempit sesuai case itu.

Bagaimana cara membuat switch yang exhaustive di TypeScript?

Tambahkan default yang meng-assign nilainya ke variabel bertipe never: default: { const unreachable: never = value; throw new Error(...) }. Kalau setiap anggota union sudah ditangani, nilainya bertipe never di sana dan kodenya lolos kompilasi. Kalau ada yang terlewat, compiler melaporkan anggota yang terlewat itu (TS2322).

Bagaimana cara menangani beberapa case dengan kode yang sama di switch TypeScript?

Tumpuk label-labelnya tanpa kode di antaranya: case "sat": case "sun": return "weekend";. Case yang kosong akan berlanjut ke case berikutnya. Opsi noFallthroughCasesInSwitch hanya melaporkan case yang punya kode tetapi tidak punya break atau return, jadi label yang ditumpuk tetap diizinkan.

Apakah switch (true) mempersempit tipe di TypeScript?

Ya, sejak TypeScript 5.3. Di switch (true) { case typeof x === "string": ... }, x dipersempit menjadi string di dalam case itu, sama seperti di if. Ini alternatif yang mudah dibaca untuk rangkaian if/else if dengan pengecekan rentang atau tipe.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai