List #

Di TypeScript, struktur data list direpresentasikan menggunakan array — tipe data bawaan yang mendapat dukungan penuh dari sistem tipe TypeScript. Tidak seperti JavaScript di mana array bisa menampung nilai apapun secara bebas, array TypeScript memiliki tipe elemen yang terdefinisi dengan jelas, sehingga setiap operasi — mulai dari push, map, filter, hingga sort — divalidasi tipenya oleh compiler. Memahami array TypeScript secara mendalam berarti memahami dua filosofi yang sering berbenturan: mutasi (mengubah array yang ada di tempat) vs immutability (menghasilkan array baru tanpa mengubah yang lama). Artikel ini membahas keduanya beserta kapan masing-masing tepat digunakan.

Mendefinisikan Array #

TypeScript menyediakan dua sintaks untuk mendeklarasikan tipe array, keduanya ekuivalen:

// Sintaks 1: T[] — lebih ringkas, lebih umum digunakan
let angka: number[] = [1, 2, 3, 4, 5];
let nama: string[] = ["Budi", "Siti", "Ahmad"];

// Sintaks 2: Array<T> — generic syntax, berguna untuk tipe kompleks
let daftarPengguna: Array<{ id: string; nama: string }> = [];
let matriks: Array<Array<number>> = [[1, 2], [3, 4], [5, 6]];

// Union type array — elemen bisa bertipe lebih dari satu
let campuran: (number | string)[] = [1, "dua", 3, "empat"];

// Array of object dengan interface
interface Produk {
  id: string;
  nama: string;
  harga: number;
  stok: number;
}

const katalog: Produk[] = [
  { id: "PRD-001", nama: "Kurma Ajwa", harga: 85_000, stok: 50 },
  { id: "PRD-002", nama: "Madu Sidr", harga: 250_000, stok: 12 },
  { id: "PRD-003", nama: "Minyak Zaitun", harga: 75_000, stok: 30 },
];

Type Inference pada Array #

TypeScript menyimpulkan tipe array secara otomatis dari nilai awal. Gunakan anotasi eksplisit hanya saat array dimulai kosong atau saat inferensi menghasilkan tipe yang terlalu lebar:

// Type inference — TypeScript menyimpulkan number[]
const nilaiOtomatis = [10, 20, 30]; // Tipe: number[]

// Perlu anotasi eksplisit — array dimulai kosong
const daftarKosong: string[] = [];  // Tanpa anotasi → tipe: never[]

// ANTI-PATTERN: Array tanpa anotasi yang dimulai kosong
const daftarSalah = []; // Tipe: never[] — tidak bisa diisi apapun!
daftarSalah.push("halo"); // ✗ Error: Argument of type 'string' is not assignable to parameter of type 'never'

ReadonlyArray — Array yang Tidak Bisa Dimodifikasi #

Untuk array yang tidak boleh diubah setelah dibuat, gunakan ReadonlyArray<T> atau sintaks readonly T[]:

// Dua sintaks yang ekuivalen
const daftarTetap: ReadonlyArray<string> = ["Senin", "Selasa", "Rabu"];
const hariKerja: readonly string[] = ["Senin", "Selasa", "Rabu", "Kamis", "Jumat"];

// Semua metode mutasi diblokir oleh compiler
// daftarTetap.push("Kamis");    // ✗ Error: Property 'push' does not exist on type 'readonly string[]'
// daftarTetap[0] = "Minggu";    // ✗ Error: Index signature in type 'readonly string[]' only permits reading
// daftarTetap.sort();           // ✗ Error: Property 'sort' does not exist on type 'readonly string[]'

// Metode yang menghasilkan array BARU tetap tersedia
const sorted = [...daftarTetap].sort(); // ✓ Buat salinan dulu, lalu sort

Mengakses Elemen Array #

Elemen array diakses melalui indeks berbasis nol. TypeScript dengan konfigurasi default menganggap akses indeks selalu menghasilkan tipe elemen (bukan undefined), yang bisa menyebabkan bug halus:

const buah: string[] = ["mangga", "pisang", "jeruk"];

// Akses normal
console.log(buah[0]); // "mangga"
console.log(buah[2]); // "jeruk"

// Jebakan: akses indeks di luar batas — tidak error kompilasi!
console.log(buah[10]); // undefined di runtime, tapi TypeScript berpikir ini string

// Solusi: aktifkan noUncheckedIndexedAccess di tsconfig.json
// Dengan opsi ini, buah[i] bertipe string | undefined — lebih akurat

Akses Aman dengan Destructuring #

Untuk mengambil elemen pertama dan selebihnya dengan aman:

const [pertama, kedua, ...selebihnya] = buah;
// pertama: string, kedua: string, selebihnya: string[]

console.log(pertama);    // "mangga"
console.log(kedua);      // "pisang"
console.log(selebihnya); // ["jeruk"]

// Untuk array yang mungkin kosong, gunakan optional atau default
const [kepala = "tidak ada"] = daftarKosong; // "tidak ada" jika kosong

Mutasi vs Immutability #

Ini adalah keputusan arsitektur paling penting saat bekerja dengan array. Metode mutasi mengubah array asli di tempat; metode immutable menghasilkan array baru tanpa mengubah yang lama.

Metode Mutasi — Mengubah Array di Tempat #

let angka: number[] = [3, 1, 4, 1, 5, 9, 2, 6];

// push / unshift — tambah elemen
angka.push(5, 3, 5);       // Tambah di akhir — [3,1,4,1,5,9,2,6,5,3,5]
angka.unshift(0);           // Tambah di awal — [0,3,1,4,1,5,9,2,6,5,3,5]

// pop / shift — hapus elemen
const akhir = angka.pop();  // Hapus dari akhir, kembalikan nilai → 5
const awal = angka.shift(); // Hapus dari awal, kembalikan nilai → 0

// splice — hapus, ganti, atau sisipkan di posisi tertentu
angka.splice(2, 2);         // Hapus 2 elemen mulai indeks 2
angka.splice(1, 0, 99, 88); // Sisipkan 99 dan 88 di indeks 1
angka.splice(0, 1, 100);    // Ganti 1 elemen di indeks 0 dengan 100

// sort dan reverse — mengubah urutan di tempat
angka.sort((a, b) => a - b);  // Urutkan ascending
angka.reverse();               // Balik urutan
Metode mutasi seperti push, pop, sort, reverse, dan splice mengubah array asli. Ini bisa menyebabkan bug yang sulit dilacak jika array yang sama dirujuk di banyak tempat. Dalam pemrograman fungsional dan state management (React, Redux), selalu gunakan metode immutable yang menghasilkan array baru.

Metode Immutable — Menghasilkan Array Baru #

const asli = [3, 1, 4, 1, 5, 9, 2, 6];

// Spread operator — cara paling idiomatik membuat salinan
const salinan = [...asli];

// concat — gabungkan array
const digabung = asli.concat([5, 3, 5]);     // Array baru
const digabung2 = [...asli, 5, 3, 5];         // Cara modern dengan spread

// slice — ambil sebagian array
const sebagian = asli.slice(2, 5);            // [4, 1, 5] — indeks 2 sampai 4

// filter — elemen yang memenuhi kondisi
const genap = asli.filter((n) => n % 2 === 0); // [4, 2, 6]

// map — transformasi setiap elemen
const dikuadratkan = asli.map((n) => n ** 2);  // [9, 1, 16, 1, 25, 81, 4, 36]

// Immutable sort — buat salinan dulu, lalu sort
const terurut = [...asli].sort((a, b) => a - b); // Asli tidak berubah
console.log(asli);    // [3, 1, 4, 1, 5, 9, 2, 6] — tetap sama
console.log(terurut); // [1, 1, 2, 3, 4, 5, 6, 9]

Metode Fungsional — Inti Pemrosesan Array #

TypeScript memberikan type inference penuh pada semua metode array fungsional. Ini membuat pipeline pemrosesan data menjadi type-safe dari ujung ke ujung.

map — Transformasi Elemen #

const produk: Produk[] = katalog; // Dari contoh sebelumnya

// Transformasi ke format tampilan
const tampilan = produk.map((p) => ({
  label: p.nama,
  harga: `Rp ${p.harga.toLocaleString("id-ID")}`,
  tersedia: p.stok > 0,
}));
// Tipe: Array<{ label: string; harga: string; tersedia: boolean }>

// Map dengan indeks
const bernomor = produk.map((p, i) => `${i + 1}. ${p.nama}`);
// ["1. Kurma Ajwa", "2. Madu Sidr", "3. Minyak Zaitun"]

filter — Menyaring dengan Type Guard #

// Filter biasa — tipe hasil sama dengan tipe input
const tersedia = produk.filter((p) => p.stok > 0);
// Tipe: Produk[]

// Filter dengan type guard — menyempitkan tipe hasil
type NilaiMungkinNull = string | null | undefined;
const campuranData: NilaiMungkinNull[] = ["satu", null, "dua", undefined, "tiga"];

// Tanpa type guard — tipe hasil masih (string | null | undefined)[]
const tanpaGuard = campuranData.filter((v) => v != null);

// Dengan type guard — tipe hasil menjadi string[]
const denganGuard = campuranData.filter((v): v is string => v != null);
console.log(denganGuard); // ["satu", "dua", "tiga"] — tipe: string[]

reduce — Akumulasi Nilai #

// Hitung total nilai belanja
const totalStokNilai = produk.reduce((total, p) => {
  return total + p.harga * p.stok;
}, 0);
// 85_000*50 + 250_000*12 + 75_000*30 = 4_250_000 + 3_000_000 + 2_250_000 = 9_500_000

// Reduce ke object — group by kategori
const perStok = produk.reduce(
  (kelompok, p) => {
    const kategori = p.stok > 20 ? "banyak" : p.stok > 5 ? "sedang" : "sedikit";
    kelompok[kategori] = [...(kelompok[kategori] ?? []), p.nama];
    return kelompok;
  },
  {} as Record<string, string[]>
);
// { banyak: ["Kurma Ajwa", "Minyak Zaitun"], sedang: ["Madu Sidr"] }

flatMap — Map lalu Flatten #

const kalimat = ["halo dunia", "typescript itu keren", "belajar setiap hari"];

// map menghasilkan string[][] — array of arrays
const kata2D = kalimat.map((k) => k.split(" "));
// [["halo", "dunia"], ["typescript", "itu", "keren"], ["belajar", "setiap", "hari"]]

// flatMap menghasilkan string[] — langsung flat
const kataFlat = kalimat.flatMap((k) => k.split(" "));
// ["halo", "dunia", "typescript", "itu", "keren", "belajar", "setiap", "hari"]

// flatMap juga berguna untuk transformasi yang menghasilkan nol atau lebih elemen
const hargaValid = produk.flatMap((p) =>
  p.harga > 0 && p.stok > 0 ? [p.harga] : [] // Hanya harga produk yang valid dan tersedia
);

Chaining Metode — Pipeline Data #

const laporanTop3 = katalog
  .filter((p) => p.stok > 0)                    // 1. Hanya yang tersedia
  .map((p) => ({                                  // 2. Hitung nilai stok
    nama: p.nama,
    nilaiStok: p.harga * p.stok,
    hargaFormatted: `Rp ${p.harga.toLocaleString("id-ID")}`,
  }))
  .sort((a, b) => b.nilaiStok - a.nilaiStok)     // 3. Urutkan dari terbesar
  .slice(0, 3);                                   // 4. Ambil top 3

// TypeScript menyimpulkan tipe akhir:
// Array<{ nama: string; nilaiStok: number; hargaFormatted: string }>

Mencari Elemen #

TypeScript memiliki beberapa metode pencarian dengan tipe kembalian yang berbeda:

const angka = [10, 25, 3, 47, 8, 31, 15];

// indexOf — kembalikan indeks pertama atau -1
const indeks = angka.indexOf(25);    // 1
const tidakAda = angka.indexOf(99);  // -1

// findIndex — cari berdasarkan kondisi, kembalikan indeks
const idxBesar = angka.findIndex((n) => n > 30); // 3 (nilai 47)

// find — cari berdasarkan kondisi, kembalikan NILAI atau undefined
const nilaiPertama = angka.find((n) => n > 20);  // 25
// Tipe: number | undefined — TypeScript tahu bisa tidak ditemukan

// findLast / findLastIndex (ES2023) — cari dari belakang
const nilaiTerakhirBesar = angka.findLast((n) => n > 20);  // 31

// includes — cek keberadaan nilai
const adaTiga = angka.includes(3);   // true
const adaSepuluh = angka.includes(10); // true

// some / every — cek kondisi
const adaYangBesar = angka.some((n) => n > 40);   // true (ada 47)
const semuaPositif = angka.every((n) => n > 0);   // true
const semuaBesar = angka.every((n) => n > 20);    // false

Pengurutan dengan Comparator #

Metode sort() tanpa argumen mengurutkan berdasarkan representasi string — ini adalah jebakan klasik untuk array angka:

// ANTI-PATTERN: sort() tanpa comparator untuk angka — bug klasik
const angkaSalah = [10, 9, 2, 21, 3];
angkaSalah.sort();
console.log(angkaSalah); // [10, 2, 21, 3, 9] — SALAH! Diurutkan sebagai string

// BENAR: Gunakan comparator untuk angka
const angkaBenar = [10, 9, 2, 21, 3];
angkaBenar.sort((a, b) => a - b); // Ascending
console.log(angkaBenar); // [2, 3, 9, 10, 21]

angkaBenar.sort((a, b) => b - a); // Descending
console.log(angkaBenar); // [21, 10, 9, 3, 2]

// Urutkan array of object berdasarkan properti
const terurut = [...katalog].sort((a, b) => a.harga - b.harga); // Ascending harga
const terurutNama = [...katalog].sort((a, b) =>
  a.nama.localeCompare(b.nama, "id")  // Urutkan string dengan locale Indonesia
);

Set — Koleksi Nilai Unik #

Set adalah struktur data yang hanya menyimpan nilai unik — tidak ada duplikat. TypeScript mendukung Set<T> dengan type safety penuh:

// Membuat Set
const angkaUnik = new Set<number>([1, 2, 3, 2, 1, 4]);
console.log(angkaUnik.size); // 4 — duplikat otomatis dihapus
console.log([...angkaUnik]);  // [1, 2, 3, 4]

// Operasi pada Set
const kategori = new Set<string>();
kategori.add("makanan");
kategori.add("minuman");
kategori.add("makanan");  // Tidak ditambahkan — sudah ada
console.log(kategori.has("makanan")); // true
console.log(kategori.size);           // 2

kategori.delete("minuman");
console.log([...kategori]); // ["makanan"]

// Pola umum: hapus duplikat dari array
const arrayDenganDuplikat = [1, 2, 3, 2, 1, 4, 3, 5];
const tanpaDuplikat = [...new Set(arrayDenganDuplikat)];
// [1, 2, 3, 4, 5]

// Operasi himpunan dengan Set
const setA = new Set([1, 2, 3, 4, 5]);
const setB = new Set([3, 4, 5, 6, 7]);

// Union (gabungan)
const union = new Set([...setA, ...setB]);
// {1, 2, 3, 4, 5, 6, 7}

// Intersection (irisan)
const intersection = new Set([...setA].filter((x) => setB.has(x)));
// {3, 4, 5}

// Difference (selisih)
const difference = new Set([...setA].filter((x) => !setB.has(x)));
// {1, 2}

Array Multidimensi #

TypeScript mendukung array multidimensi dengan tipe yang konsisten di semua dimensi:

// Matriks 2D — array of arrays
const matriks: number[][] = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];

// Akses elemen
console.log(matriks[1][2]); // 6 — baris 1, kolom 2

// Iterasi matriks
for (const baris of matriks) {
  for (const nilai of baris) {
    process.stdout.write(`${nilai} `);
  }
  console.log();
}

// Transpose matriks — contoh transformasi 2D
function transpose(mat: number[][]): number[][] {
  return mat[0].map((_, kolomIdx) => mat.map((baris) => baris[kolomIdx]));
}

console.log(transpose(matriks));
// [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

// Array of tuples — untuk data terstruktur ringan
const koordinat: [number, number][] = [
  [-6.2088, 106.8456], // Jakarta
  [-7.2575, 112.7521], // Surabaya
  [-6.9147, 107.6098], // Bandung
];

for (const [lat, lon] of koordinat) {
  console.log(`Lat: ${lat}, Lon: ${lon}`);
}

Peta Metode Array #

flowchart TD
    A[Metode Array TypeScript] --> B[Mutasi - Ubah In-Place]
    A --> C[Fungsional - Hasilkan Array Baru]
    A --> D[Pencarian]
    A --> E[Agregasi]

    B --> B1[push - tambah akhir]
    B --> B2[pop - hapus akhir]
    B --> B3[unshift - tambah awal]
    B --> B4[shift - hapus awal]
    B --> B5[splice - sisip-hapus]
    B --> B6[sort - urutkan]
    B --> B7[reverse - balik]

    C --> C1[map - transformasi]
    C --> C2[filter - saring]
    C --> C3[flatMap - map + flatten]
    C --> C4[slice - ambil sebagian]
    C --> C5[concat - gabungkan]
    C --> C6[spread ... - salinan]

    D --> D1[find - nilai pertama]
    D --> D2[findIndex - indeks pertama]
    D --> D3[indexOf - indeks eksak]
    D --> D4[includes - cek ada-tidaknya]
    D --> D5[some - ada yang memenuhi?]
    D --> D6[every - semua memenuhi?]

    E --> E1[reduce - akumulasi]
    E --> E2[join - gabung ke string]
    E --> E3[length - jumlah elemen]

    style B fill:#ff6b6b,color:#fff
    style C fill:#51cf66,color:#fff
    style D fill:#339af0,color:#fff
    style E fill:#fcc419,color:#000

Ringkasan #

  • T[] vs Array<T> — keduanya ekuivalen; gunakan T[] untuk keterbacaan di sebagian besar kasus, Array<T> saat perlu generic yang lebih kompleks.
  • Deklarasikan tipe untuk array kosongconst daftar: string[] = []; tanpa anotasi, TypeScript menyimpulkan never[] yang tidak bisa diisi apapun.
  • ReadonlyArray<T> atau readonly T[] — untuk array yang tidak boleh dimodifikasi setelah dibuat; semua metode mutasi diblokir oleh compiler.
  • Metode mutasi (push, pop, sort, splice) mengubah array asli — hati-hati jika array dirujuk di banyak tempat; gunakan [...arr].sort() untuk operasi sort yang tidak mengubah original.
  • filter dengan type guard (v): v is T menghasilkan array dengan tipe yang lebih spesifik — penting saat menyaring null atau undefined dari union type.
  • Jangan gunakan sort() tanpa comparator untuk angka[10, 9, 2].sort() menghasilkan [10, 2, 9] karena mengurutkan sebagai string; selalu gunakan sort((a, b) => a - b).
  • flatMap lebih efisien dari map lalu flat — gunakan saat transformasi menghasilkan array yang perlu di-flatten satu level.
  • Set untuk nilai unik[...new Set(arr)] adalah cara paling ringkas menghapus duplikat dari array; Set juga mendukung operasi himpunan (union, intersection, difference).
  • Chaining metode array (filter → map → sort → slice) membentuk pipeline yang ekspresif dan type-safe — TypeScript menyimpulkan tipe di setiap tahap secara otomatis.
  • Aktifkan noUncheckedIndexedAccess di tsconfig.json agar akses arr[i] menghasilkan T | undefined alih-alih hanya T — lebih aman untuk mencegah bug akses di luar batas.

← Sebelumnya: Eksepsi   Berikutnya: Map →

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