TypeScript punya perulangan yang sama dengan JavaScript: for, for...of, for...in, while, do...while, dan method array forEach. Yang ditambahkan TypeScript adalah tipenya: variabel perulangan di for...of mendapat tipe elemen, dan key di for...in selalu bertipe string.
Untuk sebagian besar perulangan array, for...of adalah pilihan utama: mudah dibaca, mendukung break, continue, dan await, serta tidak butuh anotasi.
for Loop Klasik
for (init; condition; update) adalah perulangan untuk menghitung, melangkah lebih dari satu, atau berjalan mundur. TypeScript menyimpulkan tipe penghitungnya dari nilai awalnya.
Deklarasikan penghitungnya dengan let, bukan var. Dengan let, setiap iterasi mendapat binding sendiri, jadi callback yang dibuat di dalam perulangan melihat nilai dari iterasi tersebut.
for...of: Nilai dari Array, String, dan Map
for...of bekerja pada apa pun yang iterable, dan variabel perulangannya mendapat tipe yang sesuai. Untuk mendapatkan indeksnya juga, lakukan perulangan atas array.entries(), yang menghasilkan tuple [index, value].
break keluar dari perulangan dan continue melompat ke item berikutnya, persis seperti di for loop. Detail saat runtime (iterable, generator) ada di halaman JavaScript for...of dan for...in.
forEach: Tanpa break, Tanpa await
forEach memanggil sebuah fungsi untuk setiap elemen dan mengembalikan undefined. Parameter callback-nya diberi tipe berdasarkan array, jadi tidak perlu anotasi. Ada dua hal yang tidak bisa dilakukannya:
- Berhenti lebih awal.
breakdi dalam callback adalah error kompilasi TS1107,Jump target cannot cross function boundary.returnhanya mengakhiri pemanggilan yang sedang berjalan, jadi perilakunya seperticontinue. - Menunggu pekerjaan async.
forEachmengabaikan promise yang dikembalikan callbackasync.
Jebakan async ini mudah terlewat, karena kodenya lolos kompilasi tanpa peringatan:
Callback forEach selesai sesuai urutan timer (10, 20, 30), setelah perulangannya sudah lanjut. Versi for...of menjalankannya secara berurutan. Untuk pekerjaan paralel yang tetap kamu tunggu, pakai await Promise.all(items.map(async (item) => { ... })).
for...in: Key Berupa String
for...in melakukan perulangan atas nama-nama properti enumerable sebuah object. Tipe key-nya selalu string, bahkan untuk array, yang key-nya adalah indeks dalam bentuk string. Itu membuatnya canggung untuk memberi indeks pada object yang bertipe:
index.ts(5,22): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ name: string; age: number; }'.
No index signature with a parameter of type 'string' was found on type '{ name: string; age: number; }'.
TypeScript sengaja memberi tipe string pada key: saat runtime, sebuah object bisa punya lebih banyak properti daripada yang tercantum di tipenya (structural typing mengizinkan properti tambahan), dan for...in juga menelusuri properti enumerable yang diwarisi. Jadi TypeScript tidak bisa menjanjikan bahwa key-nya adalah "name" | "age". Cara memperbaikinya ada di bagian berikutnya. Hindari for...in pada array sama sekali.
Perulangan atas Key dan Value Object
Object.entries menghasilkan pasangan [key, value] dan merupakan cara yang umum untuk melakukan perulangan atas sebuah object. Object.keys mengembalikan string[] dengan alasan yang sama seperti for...in, jadi kalau kamu tahu object-nya tidak punya key tambahan, lakukan assertion pada tipe key-nya.
Untuk data yang key-nya tidak diketahui sebelumnya, beri object itu tipe Record<string, number> atau pakai Map; keduanya dibahas di halaman dictionary.
while dan do...while
while memeriksa kondisinya sebelum setiap putaran; do...while menjalankan body-nya sekali sebelum memeriksa. Keduanya cocok untuk perulangan yang tidak menelusuri sebuah koleksi, misalnya membaca sampai suatu kondisi terpenuhi. Narrowing tetap bekerja di dalamnya: setelah pemeriksaan !== undefined di kondisi, tipe variabel itu dipersempit di dalam body.
Label, break, dan continue di Perulangan Bersarang
break biasa hanya keluar dari perulangan terdalam. Untuk keluar dari perulangan luar, beri label pada perulangan itu dan sebutkan label-nya:
Perulangan Mana yang Dipakai
| Tujuan | Perulangan |
|---|---|
| Setiap elemen array | for (const x of arr) |
| Elemen dan indeks | for (const [i, x] of arr.entries()) atau arr.forEach((x, i) => ...) |
| Berhenti lebih awal | for...of dengan break, atau find, some, every |
| Menunggu setiap langkah dengan await | for...of dengan await di dalamnya |
| Membuat array baru | map, filter (bukan perulangan) |
| Menghitung atau melangkah sebanyak n | for (let i = 0; ...; i += n) |
| Key dan value object | for (const [k, v] of Object.entries(obj)) |
| Entri Map | for (const [k, v] of map) |
| Sampai suatu kondisi terpenuhi | while |
Pertanyaan yang sering diajukan
Bagaimana cara menulis for loop di TypeScript?
Sama seperti di JavaScript: for (let i = 0; i < 5; i++) { ... }; TypeScript menyimpulkan i sebagai number. Untuk menelusuri elemen array, for (const item of items) lebih ringkas, dan item mendapat tipe elemen dari array tersebut.
Bagaimana cara keluar dari forEach di TypeScript?
Tidak bisa: break di dalam callback adalah error kompilasi TS1107 (Jump target cannot cross function boundary), dan return hanya mengakhiri pemanggilan callback yang sedang berjalan, seperti continue. Pakai for...of dengan break, atau some/find/every, yang memang dirancang untuk berhenti lebih awal.
Apa perbedaan for...of dan for...in di TypeScript?
for...of mengunjungi nilai-nilai dari sebuah iterable (elemen array, karakter string, entri Map) dengan tipe aslinya. for...in mengunjungi key properti enumerable sebuah object, yang selalu bertipe string, termasuk indeks array dalam bentuk string. Pakai for...of untuk array dan Object.entries untuk object.
Bagaimana cara melakukan perulangan atas key dan value object di TypeScript?
Pakai for (const [key, value] of Object.entries(obj)). key bertipe string dan value adalah union dari tipe-tipe propertinya. Kalau kamu butuh key bertipe keyof typeof obj, lakukan assertion: (Object.keys(obj) as (keyof typeof obj)[]), karena TypeScript sengaja memberi tipe string[] pada Object.keys.
Bisakah await dipakai di dalam forEach?
Kodenya lolos kompilasi, tetapi forEach tidak menunggu promise yang dikembalikan callback, jadi perulangannya selesai sebelum pekerjaannya selesai. Pakai for...of dengan await di dalamnya untuk pekerjaan berurutan, atau await Promise.all(items.map(async (x) => ...)) untuk menjalankannya secara paralel.