template-literalstringtipeMenengah4 mnt baca

Template Literal Types

Bangun tipe string dinamis seperti `data-${string}` untuk nama event dan kunci API, lengkap dengan error compiler saat string tidak cocok.

Analogi: Stempel dengan Kolom Isian

Bayangkan stempel karet bertuliskan "DITERIMA TANGGAL ____". Bagian "DITERIMA TANGGAL" selalu sama, kolom isian bisa diisi tanggal apa pun, tapi tidak boleh diisi nama orang. Template literal types adalah stempel versi TypeScript: pola string yang sebagian tetap, sebagian bebas, dan compiler menolak string yang tidak mengikuti pola.

Kenapa Template Literal Types Ada?

Kamu pasti sudah kenal template literal di JavaScript: halo-${nama}. TypeScript membawa ide itu ke level tipe. Sebelum fitur ini ada, pilihanmu cuma dua: tipe string yang terlalu longgar (semua string lolos, termasuk yang salah), atau union literal seperti "klik" | "hover" yang harus ditulis satu per satu dan tidak bisa digenerasi.

Template literal types mengisi celah di antaranya: pola string yang fleksibel tapi tetap diperiksa compiler. Kasus klasiknya adalah nama event, kunci cache, dan route API yang punya awalan tetap.

Contoh 1: Mengetik Nama Event dengan Awalan Tetap

Misalkan sistem event-mu mewajibkan semua nama event diawali data-:

typescript
type DataEvent = `data-${string}`;

function onEvent(event: DataEvent, handler: () => void) {
  // daftarkan handler...
}

onEvent("data-user-login", () => {}); // OK: cocok dengan pola data-*
onEvent("data-order-paid", () => {}); // OK

DataEvent menerima string apa pun asal diawali data-. Kamu dapat keamanan pola tanpa menulis ratusan nama event satu per satu.

TypeScript juga menyediakan tipe bawaan untuk mengubah kapitalisasi di dalam pola: Capitalize, Uncapitalize, Uppercase, Lowercase. Contoh populernya adalah tipe handler on + nama event:

typescript
type EventHandlerName = `on${Capitalize<string>}`;

const a: EventHandlerName = "onClick"; // OK
const b: EventHandlerName = "onSubmit"; // OK

Pola ini menolak string yang tidak diawali huruf kapital setelah on, jadi typo seperti "onclick" tertangkap sebelum program jalan.

Contoh 2: Error Nyata Saat String Tidak Cocok Pola

Lanjutkan contoh pertama, tapi kirim nama event yang salah:

typescript
type DataEvent = `data-${string}`;

function onEvent(event: DataEvent, handler: () => void) {}

onEvent("click", () => {});

Compiler menolaknya dengan pesan yang sangat jelas:

error TS2345: Argument of type '"click"' is not assignable to parameter of type '`data-${string}`'.

Perhatikan pesannya: TypeScript menampilkan polanya secara harfiah, lengkap dengan backtick. Ini jauh lebih membantu daripada error tipe string biasa karena kamu langsung tahu pola mana yang dilanggar. Pesan seperti ini juga muncul kalau kamu salah kapitalisasi, misalnya mengirim "onclick" ke tipe on${Capitalize<string>}:

typescript
type EventHandlerName = `on${Capitalize<string>}`;
const c: EventHandlerName = "onclick";
error TS2322: Type '"onclick"' is not assignable to type '`on${Capitalize<string>}`'.

Catatan teknis: Template literal types dievaluasi sepenuhnya saat compile time dan hilang total di JavaScript hasil compile. Artinya pola ini tidak bisa dipakai untuk validasi runtime: kalau string datang dari input user atau API eksternal, kamu tetap butuh pengecekan manual (misalnya startsWith("data-")) sebelum memperlakukannya sebagai DataEvent. Tipe ini menjaga kode yang kamu tulis, bukan data yang datang dari luar.

Kesalahan Umum

1. Mengira pola berlaku juga saat runtime

typescript
// SALAH: percaya compiler akan menolak data dari API
declare const dariApi: string;
onEvent(dariApi, () => {}); // lolos compile, tapi bisa crash saat jalan

// BENAR: validasi dulu di runtime
if (dariApi.startsWith("data-")) {
  onEvent(dariApi as `data-${string}`, () => {});
}

2. Lupa bahwa bagian ${string} juga menerima string kosong

typescript
type DataEvent = `data-${string}`;
// SALAH: mengira "data-" saja akan ditolak
const e: DataEvent = "data-"; // OK menurut compiler! string kosong tetap string.

// BENAR: kalau awalan saja tidak boleh, tambahkan validasi runtime
// atau gunakan pola yang lebih ketat sesuai kebutuhan.

3. Mencampuradukkan dengan union literal biasa

typescript
// SALAH: menulis semua kemungkinan satu per satu, tidak scalable
type Event = "data-login" | "data-logout" | "data-register"; // dan 97 lagi...

// BENAR: satu pola menggantikan ratusan literal
type Event = `data-${string}`;

Tantangan

Ketik Route API dengan Pola

Definisikan tipe ApiRoute sebagai template literal type berpola /api/v1/${string}. Buat fungsi fetchRoute(route: ApiRoute) lalu panggil dengan /api/v1/users (harus lolos) dan /users (harus gagal dengan error TS2345). Tulis ulang pesan error yang muncul.