Async/Await & Promise yang Bertipe
Memahami Promise<T>, menulis fungsi async dengan tipe kembalian yang benar, menunggu banyak promise dengan Promise.all, dan menangani error asynchronous secara aman.
Promise: janji yang menghasilkan nilai nanti
Operasi seperti memanggil API, membaca file, atau menunggu timer tidak selesai seketika. JavaScript membungkusnya dalam Promise — objek yang "berjanji" memberi hasil di masa depan. TypeScript menambahkan tipe hasilnya: Promise<T> = "janji yang akan menghasilkan T".
const janji: Promise<number> = Promise.resolve(42)
janji.then((n) => {
console.log(n.toFixed(1)) // n: number — dikenali otomatis
})
async / await
async membuat fungsi selalu mengembalikan Promise; await "menunggu" Promise selesai dan memberi nilainya, sehingga kode asynchronous terbaca seperti kode biasa.
interface Pengguna { id: number; nama: string }
async function ambilPengguna(id: number): Promise<Pengguna> {
// contoh: seolah memanggil server
return { id, nama: "User " + id }
}
async function tampilkan() {
const p = await ambilPengguna(1) // p: Pengguna (bukan Promise<Pengguna>)
console.log(p.nama)
}
tampilkan()
Tipe kembalian fungsi async selalu Promise<...>. Menulis : Promise<Pengguna> berarti fungsi itu return sebuah Pengguna (bukan Promise-nya) — TypeScript membungkusnya otomatis.
Lupa await = bug halus
const p = ambilPengguna(1)
console.log(p.nama) // ❌ Property 'nama' does not exist on type 'Promise<Pengguna>'. Did you forget to use 'await'?
Di sinilah TypeScript menyelamatkan: di JavaScript biasa ini hanya menghasilkan undefined tanpa peringatan.
Menjalankan beberapa promise sekaligus
const [a, b, c] = await Promise.all([
ambilPengguna(1),
ambilPengguna(2),
ambilPengguna(3),
])
// a, b, c: Pengguna — TypeScript menjaga tipe tiap posisi (tuple)
const campur = await Promise.all([ambilPengguna(1), Promise.resolve("ok"), Promise.resolve(5)])
// [Pengguna, string, number]
Dengan await berurutan, tiap panggilan menunggu yang sebelumnya; Promise.all menjalankan semuanya bersamaan (jauh lebih cepat bila tidak saling bergantung). Variasi lain: Promise.allSettled (tunggu semua, sukses maupun gagal), Promise.race (yang tercepat), Promise.any (sukses pertama).
Menangani error
async function aman(id: number): Promise<Pengguna | null> {
try {
return await ambilPengguna(id)
} catch (e) { // e: unknown (di mode strict)
if (e instanceof Error) console.log("Gagal:", e.message)
return null
}
}
Ingat dari bab 6: variabel catch bertipe unknown karena JavaScript boleh melempar apa saja (bahkan string). Selalu persempit dulu (instanceof Error).
Membungkus callback menjadi Promise
function tunggu(ms: number): Promise<void> {
return new Promise<void>((selesai) => setTimeout(selesai, ms))
}
async function demo() {
await tunggu(500)
console.log("setengah detik berlalu")
}
Awaited dan ReturnType
type HasilAmbil = Awaited<ReturnType<typeof ambilPengguna>> // Pengguna
fetch yang bertipe (di browser/Node 18+)
async function ambilData<T>(url: string): Promise<T> {
const res = await fetch(url)
if (!res.ok) throw new Error(`HTTP ${res.status}`)
return (await res.json()) as T // ⚠️ 'as T' hanya klaim, bukan jaminan — lihat bab 22
}
const todo = await ambilData<{ id: number; title: string }>("https://jsonplaceholder.typicode.com/todos/1")
Kesalahan umum pemula
- Lupa
await(TypeScript biasanya memperingatkan seperti di atas). - Memakai
awaitdi dalamforEach— callback-nya tidak ditunggu. Pakaifor...ofatauPromise.all(arr.map(...)). - Tidak menangani error sehingga muncul unhandled rejection.
- Menganggap
as Tpada hasilfetchmemvalidasi data. Ia tidak — hanya meyakinkan compiler.