Terbilang
Library yang menulis jumlah uang dalam huruf untuk faktur dan membacanya kembali, tetap tepat di ukuran berapa pun

- nilai diuji bolak-balik di setiap perubahan
- 1.000.001
- satuan terbesar yang didukung, kuadriliun
- 10¹⁵
- penolakan bertipe sebagai ganti tebakan
- 6
- dependensi runtime di library
- 0
Di halaman ini
Masalahnya
Faktur, kuitansi, dan cek di Indonesia mencantumkan jumlah uang dua kali: sekali dalam angka dan sekali dalam huruf, yang disebut terbilang. Setiap sistem akuntansi, penggajian, dan penagihan di Indonesia membutuhkannya, jadi hampir semuanya menulis fungsinya sendiri. Banyak yang keliru, dan kekeliruannya ikut tercetak di kertas.
Ejaannya punya aturan yang tidak seragam. Angka 1 di depan menjadi se- pada sepuluh, seratus, dan seribu, tetapi ejaan baku memakai satu juta, bukan sejuta. Kelompok kosong sering bocor: 1.000.001 dibaca satu juta satu, tidak pernah satu juta nol ribu satu. Lalu angka JavaScript kehilangan ketelitian di atas sekitar 9 kuadriliun. Kode yang memakainya benar sampai triliunan, lalu diam-diam menulis jumlah yang salah di faktur sungguhan.
Yang saya bangun
Library dulu, situs untuk memperagakannya
Saya membangun Terbilang sebagai library yang bisa dipakai software penagihan lain tanpa diubah. Pengguna pertama yang dituju adalah Rinci, proyek slip gaji saya, yang membutuhkannya untuk baris jumlah uang. Library ini tidak tahu apa-apa soal browser dan tidak punya dependensi runtime. Situsnya mengimpor library ini dan tidak menghitung apa pun sendiri. Saya membangun ulang seluruh situs setelah library-nya selesai, dan library-nya tidak berubah sama sekali.
Jumlah besar tetap tepat
Library hanya menerima bilangan bulat yang tersimpan tepat, berupa big integer atau string angka. Angka JavaScript biasa ditolak, tidak dikonversi, karena konversi itulah yang membuat jumlah besar menjadi salah. Serangkaian tes permanen memeriksa nilai di atas batas ketelitian. Satuan terbesar yang didukung adalah kuadriliun (10¹⁵), karena KBBI mencantumkan katanya. Batas itu juga membuat sebagian nilai yang didukung berada di atas batas ketelitian, sehingga tes tersebut tetap bermakna.
Menolak daripada menebak
Enam jenis kesalahan masing-masing mendapat jawaban bertipe yang menyebut persis apa yang gagal: jumlah terlalu besar, angka berkoma, kata yang tidak bisa dibaca, atau opsi yang saling bertentangan. Library tidak pernah mengembalikan tebakan atau hasil setengah jadi. Jumlah yang salah tapi terlihat wajar di faktur lebih buruk daripada tidak ada jumlah sama sekali. Di atas kuadriliun, pemakaiannya dalam bahasa Indonesia belum mapan, jadi library berhenti di situ dan tidak meneruskan polanya.
Huruf bisa dibaca kembali menjadi angka
Kebanyakan alat hanya bekerja satu arah. Terbilang juga membaca huruf kembali menjadi angka, dan arah ini lebih sulit. Dua ratus lima puluh ribu berarti (2×100 + 5×10) × 1.000, bukan 200 + 50.000. Karena ada dua arah, keduanya bisa saya uji satu sama lain.
Setiap angka sampai sejuta diperiksa
Ruang masalahnya terbatas, jadi saya mengujinya secara menyeluruh. Setiap nilai dari 0 sampai 1.000.000 ditulis dalam huruf, diperiksa, dibaca kembali, lalu dibandingkan dengan aslinya. Itu 1.000.001 perjalanan bolak-balik di setiap perubahan, dalam sekitar lima detik, dan build gagal kalau satu saja rusak.
Hasilnya
Library-nya sudah di-build dan siap diterbitkan, mendukung kedua format modul. Situs publiknya tersedia dalam bahasa Indonesia dan Inggris. Saat Anda mengetik, konverter menggambar kurung di atas setiap kelompok tiga angka dengan label juta atau ribu, dan kelompok kosong terlihat menghilang. Mode dokumen mencetak jumlah seperti di kuitansi: # seribu lima ratus rupiah #. Lima opsi, misalnya sejuta, atau milyar dan miliar, masing-masing mengutip pemakaian di balik kedua pilihannya. Halaman perbandingan dengan paket lain dirilis kosong, karena belum ada yang saya ukur. Saya membangunnya dalam waktu kurang dari tujuh jam pada 5 Agustus 2026.
Di balik layarDetail teknis untuk engineer
lib/sekitar 980 baris di 8 berkas: leksikon, pengelompokan, formatter, parser, opsi, dan error terstruktur. Tanpa React, DOM,Intl,Date, atau state di tingkat modul.- API:
format(bigint | string) → wordsdanparse(words) → bigint, invers persis dengan opsi yang sama. Antarmuka publiknya 2 fungsi, 8 tipe, dan 4 konstanta. - Tidak ada
parseInt,Number(), atau aritmetikanumberdi jalur nilai. Batas bilangan bulat aman JavaScript adalah 2⁵³ ≈ 9×10¹⁵. - Varian error berupa discriminated union, misalnya
di-luar-jangkauan,tipe-tidak-didukung,opsi-bertentangan. - Opsi:
sejuta,ejaanMiliar,mataUang,sen,kapitalisasi. Setiap kombinasi diuji bolak-balik dengan dirinya sendiri, dan nama kuncinya tetap karena muncul di hash URL. - tsup membangun ESM dan CJS sekaligus dengan
.d.tsdansideEffects: false.tsconfig.lib.jsonterpisah menjaga tipe DOM dan Next keluar dari deklarasi. Versi0.0.0,files: ["dist"], lisensi MIT. - Skrip survei (
pnpm survey:record) mencatat versi paket dan tanggal pengukuran. Skrip ini sekaligus menjadi tes diferensial: setiap perbedaan harus diklasifikasikan sebagai bug kami, bug mereka, atau varian yang sah. Saat inidata/survey/hasil.jsonberisi array kosong. - Situsnya static export Next.js 14, 4 rute × 2 bahasa. Tema malam menukar variabel CSS lewat
data-tema="malam"yang dipasang sebelum render pertama. State konverter disimpan di hash URL. - Sekitar 4.370 baris TypeScript, 26 commit.
Tangkapan layar
Sedang merekrut, atau membangun hal serupa?
Saya terbuka untuk posisi full-time dan proyek freelance tertentu.