Menu

Promise di TypeScript: Promise<T>, Promise.all, allSettled

Cara memberi tipe pada promise di TypeScript: tipe Promise<T>, memberi tipe pada new Promise dan resolve, bagaimana then mengubah tipe, kenapa catch memberimu any, Promise.all dengan hasil tuple, tipe hasil Promise.allSettled, dan membungkus API callback dalam promise bertipe.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Di TypeScript, sebuah promise bertipe Promise<T>, dengan T adalah tipe nilai yang dihasilkannya saat resolve. Fungsi yang mengembalikan promise mendeklarasikannya di tipe kembaliannya, dan nilai yang kamu dapat dari then atau await bertipe T.

Mekanisme promise (state, antrean microtask, chaining) adalah JavaScript biasa, dibahas di promise JavaScript. Halaman ini membahas tipenya.

Memberi Tipe pada new Promise dan resolve

Kalau new Promise adalah nilai kembalian fungsi yang tipe kembaliannya dideklarasikan, T berasal dari situ. Kalau berdiri sendiri, TypeScript tidak menyimpulkan T dari pemanggilan resolve, dan kamu mendapat Promise<unknown>. Berikan argumen tipenya secara eksplisit:

Ada dua detail. resolve diberi tipe dari T, jadi resolve("42") di Promise<number> adalah error kompilasi. Lalu resolve() tanpa argumen hanya diperbolehkan kalau T memuat void: di Promise<number> hasilnya error TS2794 (Expected 1 arguments, but got 0. Did you forget to include 'void' in your type argument to 'Promise'?).

Sisi reject tidak bertipe. Tidak ada Promise<T, E>: sebuah promise bisa reject dengan nilai apa pun.

then, catch dan finally

Setiap then mengembalikan promise baru yang tipenya ditentukan oleh apa yang dikembalikan callback-nya. Kalau callback mengembalikan promise, TypeScript membukanya, jadi kamu tidak akan pernah mendapat Promise<Promise<T>>.

Parameter callback catch diberi tipe any di standard library, bukan unknown. Tidak ada yang mencegahmu menulis e.message pada nilai yang mungkin berupa string. Anotasi sebagai unknown, seperti di atas, lalu persempit tipenya sebelum dipakai. try/catch di sekitar await lebih baik: dengan strict, variabel catch-nya sudah bertipe unknown (lihat penanganan error).

Promise.all Mengembalikan Tuple

Kalau diberi array literal berisi promise dengan tipe berbeda, Promise.all mengembalikan promise berisi tuple, dengan setiap posisi mempertahankan tipenya sendiri:

Nilai yang bukan promise boleh dicampur dan diteruskan apa adanya. Promise.all langsung reject begitu satu input reject, dan hasil lainnya hilang. Promise.race resolve atau reject mengikuti yang pertama selesai dan bertipe union dari semua input; Promise.any resolve dengan keberhasilan pertama dan reject dengan AggregateError hanya kalau semua input gagal.

Promise.allSettled dan Tipe Hasilnya

Promise.allSettled menunggu setiap input dan tidak pernah reject. Setiap hasil adalah PromiseSettledResult<T>, sebuah union yang kamu persempit dengan field status:

r.value hanya ada setelah pengecekan status, karena varian rejected tidak punya value. reason bertipe any, dengan alasan yang sama seperti di catch. filter memakai type predicate supaya array hasil saringannya bertipe hasil fulfilled.

Membungkus API Callback dalam Promise

API lama melaporkan hasilnya lewat callback, sering dengan gaya Node (err, result) => void. Bungkus sekali dalam fungsi yang mengembalikan promise bertipe, dan sisa kodenya bisa memakai await:

Di Node, util.promisify melakukan hal ini untuk fungsi yang mengikuti konvensi (err, result), dan banyak module bawaan sudah punya versi promise (node:fs/promises, node:timers/promises).

Kesalahan Umum

  • Mengembalikan T padahal signature-nya Promise<T>, atau sebaliknya. Fungsi non-async yang dideklarasikan Promise<User> harus mengembalikan promise; fungsi async mengembalikannya secara otomatis.
  • Lupa menangani promise. Pemanggilan seperti save(user); tanpa await, then atau catch tetap lolos kompilasi, dan rejection-nya menjadi unhandled rejection (yang secara default menghentikan proses Node). Aturan typescript-eslint no-floating-promises menangkap kasus seperti ini.
  • Memercayai tipe .catch((e) => ...). e-nya bertipe any. Anotasi sebagai unknown.
  • Memakai new Promise di sekitar sesuatu yang sudah mengembalikan promise. Cukup return atau await promise yang sudah ada.

Pertanyaan yang sering diajukan

Apa itu Promise<T> di TypeScript?

Promise<T> adalah tipe promise yang resolve dengan nilai bertipe T. Fungsi yang mengembalikan Promise<string> memberikan promise yang callback then-nya, atau await-nya, menghasilkan string. Promise yang resolve tanpa nilai adalah Promise<void>.

Bagaimana cara memberi tipe pada new Promise di TypeScript?

Berikan argumen tipenya: new Promise<number>((resolve, reject) => ...). Tanpa itu, TypeScript tidak bisa menyimpulkan nilainya dari pemanggilan resolve dan hasilnya Promise<unknown>. Untuk promise yang resolve tanpa nilai apa pun, pakai new Promise<void>(resolve => ...) supaya resolve() tanpa argumen diperbolehkan.

Apa tipe error di catch sebuah promise?

any. Parameter reason milik callback catch diberi tipe any di standard library, karena apa saja bisa di-throw atau di-reject. Anotasi sendiri sebagai unknown (.catch((e: unknown) => ...)) lalu persempit dengan instanceof Error sebelum memakainya.

Bagaimana Promise.all bekerja dengan tipe di TypeScript?

Promise.all pada array literal mengembalikan tipe tuple dengan satu elemen per input, sesuai urutannya: Promise.all([getUser(), getCount()]) adalah Promise<[User, number]>, jadi destructuring memberi setiap nilai tipenya sendiri. Pada array bertipe sama, T[], hasilnya Promise<T[]>.

Apa perbedaan Promise.all dan Promise.allSettled?

Promise.all langsung reject begitu salah satu input reject. Promise.allSettled selalu resolve, dengan array berisi object PromiseSettledResult<T>: { status: "fulfilled", value } atau { status: "rejected", reason }. Cek status untuk mempersempit tipe masing-masing.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai