Strings #

String adalah tipe data yang paling sering dijumpai di hampir setiap program — dari memproses input pengguna, membangun query, memformat pesan, hingga memanipulasi URL dan path. TypeScript mewarisi seluruh kemampuan string JavaScript yang sangat kaya, ditambah type system yang memastikan kamu tidak secara tidak sengaja memanggil metode string pada nilai yang bukan string. Memahami metode string bawaan secara mendalam — kapan menggunakan mana, dan jebakan apa yang harus dihindari — adalah keterampilan dasar yang langsung berdampak pada kualitas kode sehari-hari.

Membuat String #

TypeScript mendukung tiga cara penulisan string literal, masing-masing dengan karakteristiknya sendiri.

// single quote dan double quote — identik secara fungsional
const nama = 'Budi Santoso';
const kota = "Jakarta";

// template literal (backtick) — mendukung interpolasi dan multiline
const sapaan = `Halo, ${nama}! Kamu tinggal di ${kota}.`;

// multiline dengan template literal — tidak perlu \n
const pesan = `
  Selamat datang, ${nama}.
  Akun kamu telah aktif.
  Silakan login untuk melanjutkan.
`.trim();

// ANTI-PATTERN: konkatenasi string untuk multiline
const pesanSalah =
  "Selamat datang, " + nama + ".\n" +
  "Akun kamu telah aktif.\n" +   // ✗ susah dibaca, rawan kesalahan
  "Silakan login untuk melanjutkan.";

// BENAR: template literal jauh lebih bersih
const pesanBenar = `Selamat datang, ${nama}.
Akun kamu telah aktif.
Silakan login untuk melanjutkan.`;

String di JavaScript dan TypeScript bersifat immutable — setiap operasi yang tampaknya “mengubah” string sebenarnya membuat string baru. Ini penting dipahami saat kamu melakukan banyak operasi string dalam loop.

// string immutable — s tidak berubah
let s = "hello";
s.toUpperCase(); // ✗ tidak mengubah s
console.log(s);  // "hello" — masih sama

// BENAR: simpan hasilnya
const upper = s.toUpperCase();
console.log(upper); // "HELLO"

Panjang dan Akses Karakter #

const teks = "TypeScript";

// length — jumlah karakter (code unit, bukan code point)
console.log(teks.length); // 10

// akses karakter berdasarkan indeks
console.log(teks[0]);        // "T"
console.log(teks.at(0));     // "T" — sama seperti [0]
console.log(teks.at(-1));    // "t" — indeks negatif dari belakang
console.log(teks.at(-3));    // "i" — tiga dari belakang

// ANTI-PATTERN: akses indeks negatif dengan bracket notation
console.log(teks[-1]);       // undefined — bukan "t" ✗

// charAt — mirip bracket notation tapi mengembalikan "" jika di luar batas
console.log(teks.charAt(0));   // "T"
console.log(teks.charAt(100)); // "" (string kosong)
console.log(teks[100]);        // undefined

Metode at() diperkenalkan di ES2022 dan merupakan cara yang lebih bersih untuk mengakses karakter dari belakang — gunakan ini daripada teks[teks.length - 1].


Pencarian dan Pengecekan #

Mengecek Keberadaan Substring #

const kalimat = "TypeScript adalah bahasa pemrograman yang kuat.";

// includes — apakah substring ada? (case-sensitive)
console.log(kalimat.includes("TypeScript")); // true
console.log(kalimat.includes("typescript")); // false — case-sensitive
console.log(kalimat.includes("bahasa", 20)); // true — cari mulai indeks 20

// startsWith dan endsWith
console.log(kalimat.startsWith("TypeScript")); // true
console.log(kalimat.startsWith("bahasa", 22)); // true — mulai dari indeks 22
console.log(kalimat.endsWith("kuat."));         // true
console.log(kalimat.endsWith("kuat", 44));      // true — anggap string berakhir di indeks 44

// ANTI-PATTERN: menggunakan indexOf untuk cek keberadaan
if (kalimat.indexOf("TypeScript") !== -1) { // ✗ verbose dan tidak ekspresif
  console.log("ada");
}

// BENAR: gunakan includes untuk keterbacaan
if (kalimat.includes("TypeScript")) { // ✓ lebih jelas maksudnya
  console.log("ada");
}

Mencari Posisi #

const teks = "satu dua tiga dua satu";

// indexOf — posisi pertama ditemukan, -1 jika tidak ada
console.log(teks.indexOf("dua"));     // 5
console.log(teks.indexOf("dua", 6)); // 14 — cari mulai indeks 6
console.log(teks.indexOf("empat"));   // -1

// lastIndexOf — posisi terakhir ditemukan
console.log(teks.lastIndexOf("dua"));  // 14
console.log(teks.lastIndexOf("satu")); // 17

// search — mencari dengan regex, mengembalikan posisi atau -1
console.log(teks.search(/dua/));       // 5
console.log(teks.search(/[0-9]+/));   // -1 (tidak ada angka)

// match — mengembalikan hasil pencarian regex
const angka = "Harga: 15000 dan 25000";
const hasilMatch = angka.match(/\d+/g); // flag g untuk semua kemunculan
console.log(hasilMatch); // ["15000", "25000"]

// matchAll — iterator untuk semua kemunculan dengan grup capture
const teksLink = "Kunjungi example.com dan test.org";
const regexDomain = /(\w+)\.(\w+)/g;
for (const match of teksLink.matchAll(regexDomain)) {
  console.log(`Domain: ${match[0]}, nama: ${match[1]}, tld: ${match[2]}`);
}
// Domain: example.com, nama: example, tld: com
// Domain: test.org, nama: test, tld: org

Ekstraksi Substring #

const teks = "Pemrograman TypeScript";
//            0123456789...

// slice(mulai, akhir) — akhir tidak termasuk, mendukung indeks negatif
console.log(teks.slice(0, 11));   // "Pemrograman"
console.log(teks.slice(12));      // "TypeScript"
console.log(teks.slice(-10));     // "TypeScript" — 10 karakter dari belakang
console.log(teks.slice(-10, -6)); // "Type"

// substring(mulai, akhir) — mirip slice tapi tidak mendukung indeks negatif
console.log(teks.substring(0, 11));  // "Pemrograman"
console.log(teks.substring(12));     // "TypeScript"
console.log(teks.substring(-5));     // diperlakukan sebagai 0 — mengembalikan seluruh string

// ANTI-PATTERN: gunakan substr() yang sudah deprecated
console.log(teks.substr(12, 10)); // ✗ deprecated — jangan digunakan

// BENAR: gunakan slice() — lebih konsisten dan mendukung indeks negatif
console.log(teks.slice(12, 22)); // ✓ "TypeScript"

Pilih slice() daripada substring() untuk konsistensi — slice() mendukung indeks negatif dan berperilaku lebih predictable saat argumen tidak valid.


Transformasi Teks #

Kapitalisasi #

const teks = "hELLO wORLD";

// toUpperCase dan toLowerCase
console.log(teks.toUpperCase()); // "HELLO WORLD"
console.log(teks.toLowerCase()); // "hello world"

// capitalize first letter — tidak ada metode bawaan, buat sendiri
function capitalize(str: string): string {
  if (!str) return str;
  return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}

console.log(capitalize("typeScript")); // "Typescript"

// title case — kapitalkan setiap kata
function toTitleCase(str: string): string {
  return str
    .toLowerCase()
    .split(" ")
    .map((kata) => kata.charAt(0).toUpperCase() + kata.slice(1))
    .join(" ");
}

console.log(toTitleCase("budi santoso dari jakarta")); // "Budi Santoso Dari Jakarta"

// camelCase ke snake_case — umum untuk konversi nama field
function toSnakeCase(str: string): string {
  return str
    .replace(/([A-Z])/g, "_$1")
    .toLowerCase()
    .replace(/^_/, ""); // hapus underscore di awal jika ada
}

console.log(toSnakeCase("namaLengkap"));   // "nama_lengkap"
console.log(toSnakeCase("createdAtDate")); // "created_at_date"

// snake_case ke camelCase
function toCamelCase(str: string): string {
  return str.replace(/_([a-z])/g, (_, huruf) => huruf.toUpperCase());
}

console.log(toCamelCase("nama_lengkap"));    // "namaLengkap"
console.log(toCamelCase("created_at_date")); // "createdAtDate"

Trim — Menghapus Whitespace #

const input = "   Budi Santoso   ";

// trim — hapus whitespace di kedua sisi
console.log(input.trim());       // "Budi Santoso"

// trimStart / trimEnd — hapus whitespace di satu sisi
console.log(input.trimStart()); // "Budi Santoso   "
console.log(input.trimEnd());   // "   Budi Santoso"

// ANTI-PATTERN: gunakan trimLeft/trimRight yang sudah deprecated
console.log(input.trimLeft());  // ✗ deprecated
console.log(input.trimRight()); // ✗ deprecated

// trim untuk input form — pola yang sangat umum
function bersihkanInput(nilai: string): string {
  return nilai.trim().replace(/\s+/g, " "); // juga normalisasi spasi di tengah
}

console.log(bersihkanInput("  Budi   Santoso  ")); // "Budi Santoso"

Padding dan Pengisian #

// padStart — tambah karakter di awal hingga panjang tertentu
console.log("5".padStart(3, "0"));    // "005"
console.log("42".padStart(5, "0"));   // "00042"
console.log("abc".padStart(6));        // "   abc" — default padding spasi

// padEnd — tambah karakter di akhir
console.log("Budi".padEnd(10, "."));  // "Budi......"
console.log("100".padEnd(6, "0"));    // "100000"

// use case: format nomor invoice atau kode
function formatNomorInvoice(nomor: number): string {
  return `INV-${String(nomor).padStart(6, "0")}`;
}

console.log(formatNomorInvoice(1));    // "INV-000001"
console.log(formatNomorInvoice(1234)); // "INV-001234"

// use case: tampilkan tabel teks sederhana
const data = [
  ["Nama", "Umur", "Kota"],
  ["Budi", "28", "Jakarta"],
  ["Sari", "25", "Bandung"],
];

for (const baris of data) {
  console.log(
    baris[0].padEnd(15) +
    baris[1].padEnd(8) +
    baris[2]
  );
}
// Nama           Umur    Kota
// Budi           28      Jakarta
// Sari           25      Bandung

Repeat dan Pengulangan #

// repeat — ulangi string sebanyak N kali
console.log("ab".repeat(3));    // "ababab"
console.log("-".repeat(40));    // "----------------------------------------"
console.log("  ".repeat(4));   // "        " (8 spasi untuk indentasi)

// use case: separator dan indentasi
function cetakJudul(judul: string): void {
  const separator = "=".repeat(judul.length + 4);
  console.log(separator);
  console.log(`= ${judul} =`);
  console.log(separator);
}

cetakJudul("Laporan Penjualan");
// ====================
// = Laporan Penjualan =
// ====================

Penggantian Teks #

replace dan replaceAll #

const teks = "Saya suka kopi. Kamu suka kopi juga?";

// replace — hanya mengganti kemunculan PERTAMA
console.log(teks.replace("kopi", "teh"));
// "Saya suka teh. Kamu suka kopi juga?" — kopi kedua tidak terganti

// ANTI-PATTERN: menggunakan replace untuk mengganti semua kemunculan
console.log(teks.replace(/kopi/g, "teh")); // ✓ dengan regex flag g — bisa, tapi verbose

// BENAR: gunakan replaceAll untuk mengganti semua kemunculan
console.log(teks.replaceAll("kopi", "teh"));
// "Saya suka teh. Kamu suka teh juga?"

// replace dengan fungsi — transformasi dinamis
const teksAngka = "Harga: 15000, Diskon: 2000, Total: 13000";
const hasilFormat = teksAngka.replace(/\d+/g, (angka) => {
  return Number(angka).toLocaleString("id-ID");
});
console.log(hasilFormat);
// "Harga: 15.000, Diskon: 2.000, Total: 13.000"

// replace dengan grup capture — sangat powerful untuk transformasi teks
const tanggalUS = "2024-01-15"; // format ISO: YYYY-MM-DD
const tanggalID = tanggalUS.replace(
  /(\d{4})-(\d{2})-(\d{2})/,
  "$3/$2/$1" // DD/MM/YYYY
);
console.log(tanggalID); // "15/01/2024"

// sanitasi HTML — replace karakter khusus
function escapeHtml(teks: string): string {
  return teks
    .replaceAll("&", "&")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");
}

console.log(escapeHtml('<script>alert("xss")</script>'));
// "&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;"

Split dan Join #

split dan join sering bekerja berpasangan — memecah string menjadi array, memproses tiap elemen, lalu menggabungkannya kembali.

const kalimat = "TypeScript adalah bahasa yang kuat dan ekspresif";

// split berdasarkan string
const kata = kalimat.split(" ");
// ["TypeScript", "adalah", "bahasa", "yang", "kuat", "dan", "ekspresif"]

// split dengan limit — maksimal N elemen
const duaKata = kalimat.split(" ", 2);
// ["TypeScript", "adalah"]

// split berdasarkan regex
const csvLine = "Budi,Santoso,,Jakarta,28";
const kolom = csvLine.split(",");
// ["Budi", "Santoso", "", "Jakarta", "28"]

// split setiap karakter
const huruf = "TypeScript".split("");
// ["T", "y", "p", "e", "S", "c", "r", "i", "p", "t"]

// join — gabungkan array menjadi string
const tags = ["typescript", "nodejs", "backend"];
console.log(tags.join(", "));  // "typescript, nodejs, backend"
console.log(tags.join(" | ")); // "typescript | nodejs | backend"
console.log(tags.join(""));    // "typescriptnodejsbackend"

// pola umum: split → transform → join
const slug = "Panduan TypeScript untuk Pemula"
  .toLowerCase()
  .trim()
  .replace(/[^\w\s-]/g, "")   // hapus karakter non-alphanumeric
  .replace(/\s+/g, "-")        // ganti spasi dengan dash
  .replace(/-+/g, "-");        // normalisasi dash berulang

console.log(slug); // "panduan-typescript-untuk-pemula"

Template Literal Lanjutan #

Tagged Template Literal #

Tagged template adalah fitur yang jarang digunakan tapi sangat powerful — memungkinkan kamu memproses template literal dengan fungsi kustom.

// tag function menerima array strings dan nilai-nilai interpolasi
function highlight(strings: TemplateStringsArray, ...values: unknown[]): string {
  return strings.reduce((hasil, str, i) => {
    const nilai = values[i - 1];
    return hasil + `**${nilai}**` + str;
  });
}

const nama = "Budi";
const skor = 95;
console.log(highlight`Selamat, ${nama}! Skor kamu adalah ${skor}.`);
// "Selamat, **Budi**! Skor kamu adalah **95**."

// use case nyata: SQL query yang aman dari injection
function sql(strings: TemplateStringsArray, ...values: unknown[]): {
  query: string;
  params: unknown[];
} {
  const params: unknown[] = [];
  const query = strings.reduce((hasil, str, i) => {
    if (i > 0) {
      params.push(values[i - 1]);
      return hasil + `$${params.length}` + str; // placeholder PostgreSQL
    }
    return str;
  });

  return { query, params };
}

const userId = 42;
const status = "aktif";
const { query, params } = sql`
  SELECT * FROM users
  WHERE id = ${userId}
  AND status = ${status}
`;

console.log(query);
// SELECT * FROM users WHERE id = $1 AND status = $2

console.log(params);
// [42, "aktif"]

String Types di TypeScript #

TypeScript memiliki fitur unik yang tidak ada di JavaScript biasa — kemampuan memanipulasi string di level tipe.

// Utility types untuk string
type NamaEvent = "klik" | "hover" | "fokus";

// Capitalize — huruf pertama kapital
type EventCapitalized = Capitalize<NamaEvent>;
// "Klik" | "Hover" | "Fokus"

// Uncapitalize — huruf pertama kecil
type EventLower = Uncapitalize<"Klik" | "Hover">;
// "klik" | "hover"

// Uppercase — semua kapital
type EventUpper = Uppercase<NamaEvent>;
// "KLIK" | "HOVER" | "FOKUS"

// Lowercase — semua kecil
type EventLower2 = Lowercase<"KLIK" | "HOVER">;
// "klik" | "hover"

// Template literal types — bangun union type dari kombinasi string
type Sisi = "atas" | "bawah" | "kiri" | "kanan";
type PropertyMargin = `margin-${Sisi}`;
// "margin-atas" | "margin-bawah" | "margin-kiri" | "margin-kanan"

type PropCSS = `${"padding" | "margin"}-${Sisi}`;
// "padding-atas" | "padding-bawah" | ... | "margin-atas" | ...

// Gunakan untuk type-safe CSS properties atau event handler names
type NamaHandler = `on${Capitalize<NamaEvent>}`;
// "onKlik" | "onHover" | "onFokus"

interface KomponenProps {
  onKlik?: () => void;
  onHover?: () => void;
  onFokus?: () => void;
}

Konversi dan Parsing #

// number ke string
const angka = 12345.678;

console.log(String(angka));           // "12345.678"
console.log(angka.toString());        // "12345.678"
console.log(angka.toString(2));       // biner: "11000000111001.1010..."
console.log(angka.toString(16));      // hex: "3039.ad..."
console.log(angka.toFixed(2));        // "12345.68" — 2 desimal
console.log(angka.toPrecision(6));    // "12345.7" — 6 digit signifikan
console.log(angka.toExponential(2));  // "1.23e+4" — notasi ilmiah

// format angka dengan locale
console.log(angka.toLocaleString("id-ID"));
// "12.345,678" — format Indonesia

console.log(angka.toLocaleString("id-ID", {
  style: "currency",
  currency: "IDR",
  minimumFractionDigits: 0,
}));
// "Rp 12.346"

// string ke number
console.log(Number("42"));        // 42
console.log(Number("3.14"));      // 3.14
console.log(Number(""));          // 0
console.log(Number("abc"));       // NaN
console.log(parseInt("42px"));    // 42 — ambil angka di awal
console.log(parseFloat("3.14em")); // 3.14
console.log(parseInt("0xFF", 16)); // 255 — parse hex

// ANTI-PATTERN: menggunakan + unary untuk konversi
const hasil = +"42"; // ✗ tidak jelas maksudnya

// BENAR: Number() lebih eksplisit
const hasilBenar = Number("42"); // ✓ jelas ini konversi ke number

// cek apakah string adalah angka valid
function isNumeric(str: string): boolean {
  return !isNaN(Number(str)) && str.trim() !== "";
}

console.log(isNumeric("42"));    // true
console.log(isNumeric("3.14")); // true
console.log(isNumeric("abc"));  // false
console.log(isNumeric(""));     // false

Unicode dan Karakter Khusus #

// charCodeAt — kode UTF-16 code unit
console.log("A".charCodeAt(0)); // 65
console.log("a".charCodeAt(0)); // 97

// codePointAt — kode Unicode code point (lebih akurat untuk emoji/karakter luar BMP)
console.log("😀".codePointAt(0)); // 128512
console.log("A".codePointAt(0));  // 65

// fromCharCode dan fromCodePoint — buat string dari kode
console.log(String.fromCharCode(65, 66, 67));   // "ABC"
console.log(String.fromCodePoint(128512));       // "😀"

// normalisasi Unicode — penting untuk perbandingan string multibahasa
const s1 = "café"; // é sebagai satu karakter
const s2 = "cafe\u0301"; // e + combining accent

console.log(s1 === s2);                     // false — representasi berbeda
console.log(s1.normalize() === s2.normalize()); // true — setelah normalisasi NFC

// panjang string dengan emoji — masalah umum
const emoji = "😀";
console.log(emoji.length);       // 2 — karena emoji adalah surrogate pair (2 code unit)
console.log([...emoji].length);  // 1 — panjang yang benar menggunakan spread/iterator

// iterasi string dengan benar untuk karakter di luar BMP
const teksEmoji = "Halo 😀!";
for (const char of teksEmoji) {
  console.log(char); // mengiterasi per code point, bukan code unit
}
// H, a, l, o, ' ', 😀, !
Saat bekerja dengan string yang mungkin mengandung emoji atau karakter di luar BMP (Basic Multilingual Plane), gunakan [...str].length atau Array.from(str).length untuk mendapatkan panjang yang akurat berdasarkan code point, bukan .length yang menghitung code unit UTF-16.

Pola Umum di Aplikasi Nyata #

Validasi dan Sanitasi Input #

// validasi email sederhana
function isEmailValid(email: string): boolean {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return regex.test(email.trim());
}

// validasi nomor telepon Indonesia
function isPhoneValid(phone: string): boolean {
  const normalized = phone.replace(/[\s\-\(\)]/g, ""); // hapus pemisah
  return /^(\+62|62|0)[0-9]{8,12}$/.test(normalized);
}

// normalisasi nomor telepon ke format +62
function normalizePhone(phone: string): string {
  const cleaned = phone.replace(/[\s\-\(\)]/g, "");
  if (cleaned.startsWith("0")) return "+62" + cleaned.slice(1);
  if (cleaned.startsWith("62")) return "+" + cleaned;
  return cleaned; // sudah +62 atau format lain
}

console.log(normalizePhone("081234567890"));  // "+6281234567890"
console.log(normalizePhone("6281234567890")); // "+6281234567890"

Membangun URL dan Query String #

// membangun URL dengan query parameter
function buildURL(base: string, params: Record<string, string | number | boolean>): string {
  const url = new URL(base);
  for (const [key, value] of Object.entries(params)) {
    if (value !== undefined && value !== null && value !== "") {
      url.searchParams.set(key, String(value));
    }
  }
  return url.toString();
}

console.log(buildURL("https://api.example.com/produk", {
  q: "laptop gaming",
  kategori: "elektronik",
  hargaMax: 10000000,
  halaman: 1,
}));
// "https://api.example.com/produk?q=laptop+gaming&kategori=elektronik&hargaMax=10000000&halaman=1"

// truncate teks untuk preview
function truncate(teks: string, maxLength: number, suffix = "..."): string {
  if (teks.length <= maxLength) return teks;
  return teks.slice(0, maxLength - suffix.length).trimEnd() + suffix;
}

console.log(truncate("Ini adalah teks yang sangat panjang sekali", 20));
// "Ini adalah teks..."

// highlight keyword dalam teks (untuk hasil pencarian)
function highlightKeyword(teks: string, keyword: string): string {
  const regex = new RegExp(`(${keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`, "gi");
  return teks.replace(regex, "<mark>$1</mark>");
}

console.log(highlightKeyword("TypeScript sangat kuat dan TypeScript sangat populer", "typescript"));
// "<mark>TypeScript</mark> sangat kuat dan <mark>TypeScript</mark> sangat populer"

Interpolasi dan Format Pesan #

// format pesan dengan placeholder — berguna untuk i18n
function format(template: string, params: Record<string, string | number>): string {
  return template.replace(/\{(\w+)\}/g, (_, key) => {
    return key in params ? String(params[key]) : `{${key}}`;
  });
}

const template = "Halo, {nama}! Kamu punya {jumlah} pesan baru.";
console.log(format(template, { nama: "Budi", jumlah: 5 }));
// "Halo, Budi! Kamu punya 5 pesan baru."

// plural sederhana
function plural(jumlah: number, singular: string, jamak: string): string {
  return `${jumlah} ${jumlah === 1 ? singular : jamak}`;
}

console.log(plural(1, "item", "items"));  // "1 item"
console.log(plural(5, "item", "items"));  // "5 items"

Ringkasan #

  • Gunakan template literal untuk interpolasi dan string multiline — jauh lebih bersih dari konkatenasi dengan +.
  • at() untuk akses karakter — mendukung indeks negatif (str.at(-1)) dan lebih ekspresif dari str[str.length - 1].
  • includes() bukan indexOf() untuk cek keberadaan substring — lebih eksplisit dan mudah dibaca.
  • slice() bukan substring() untuk ekstraksi substring — mendukung indeks negatif dan berperilaku lebih predictable.
  • replaceAll() bukan replace(/pattern/g) untuk mengganti semua kemunculan — lebih jelas niatnya.
  • Jangan gunakan substr(), trimLeft(), trimRight() — ketiganya sudah deprecated; gunakan slice(), trimStart(), dan trimEnd().
  • String bersifat immutable — setiap metode selalu mengembalikan string baru; simpan hasilnya ke variabel.
  • Gunakan [...str].length untuk panjang string yang mengandung emoji atau karakter di luar BMP — .length menghitung code unit, bukan code point.
  • Tagged template literal memungkinkan pemrosesan kustom — sangat berguna untuk SQL builder yang aman dari injection atau HTML yang di-escape otomatis.
  • Template literal types TypeScript (Capitalize, Uppercase, Lowercase) memungkinkan manipulasi string di level tipe untuk type safety yang lebih ketat.

← Sebelumnya: Artikel & Sumber Daya   Berikutnya: IO →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact