Aku Pindah 5.000 Baris JavaScript ke TypeScript Ternyata Errornya Gila-Gilaan Tapi Akhirnya Gini (Studi Kasus)
Mungkin kamu pernah dengar pepatah di dunia ngoding: "Kalau JavaScript itu seperti pisau Swiss Army yang hebat, maka TypeScript itu adalah pedang laser yang dilengkapi asuransi."
Kami di Javapixa Creative Studio sering banget menghadapi klien dengan codebase yang sudah ‘matang’—atau lebih tepatnya, sudah mulai bau. Kali ini, studi kasusnya adalah migrasi masif dari 5.000 baris kode JavaScript murni ke TypeScript. Lima ribu baris kode ini bukan proyek iseng, ini adalah inti dari sebuah dashboard manajemen internal yang sangat kompleks.
Kami tahu, janji TypeScript itu manis: catch bugs before runtime, better developer experience, dan maintainability yang jauh lebih baik. Tapi, proses migrasinya? Jujur, kami hampir menyerah di minggu pertama. Errornya gila-gilaan. Rasanya seperti membuka keran, dan bukannya air yang keluar, malah ribuan notifikasi merah yang menyapa.
Artikel ini bukan tentang mengapa kamu harus pindah (itu sudah jelas), tapi tentang bagaimana kami berhasil pindah tanpa membakar server, dan tips aplikatif apa yang kami temukan untuk menaklukkan lautan error itu.
Kenapa Kami Memutuskan Pindah Kapal?
Lima ribu baris JS yang kami tangani ini awalnya ditulis dengan paradigma yang sangat fleksibel (baca: sangat longgar). Setiap fungsi bisa menerima apa saja, dan mengembalikan apa saja. Masalah mulai muncul ketika junior developer baru bergabung atau ketika kami harus melakukan refactoring di modul yang tidak kami sentuh selama enam bulan.
Contoh klasiknya: sebuah fungsi yang seharusnya menerima objek pengguna, tapi di satu file lain, malah di-pass ID pengguna (sebagai string). JavaScript diam saja. TS tidak. Ia berteriak, dan teriakannya benar.
Keputusan migrasi adalah investasi jangka panjang. Kami di Javapixa percaya bahwa produk yang scalable dan reliable harus dibangun di atas fondasi yang kokoh. Dan pondasi 5.000 baris JS murni sudah mulai retak.
Fase 1: Shock dan Tsunami Error (Dari 5.000 Baris Menjadi 3.000 Error)
Langkah pertama terdengar sederhana: mengubah ekstensi file dari .js menjadi .ts atau .tsx.
Begitu kami selesai me-rename file utama, kompilator TypeScript (TSC) langsung bekerja. Dan hasilnya... bencana yang indah.
Dari 5.000 baris, kami langsung mendapatkan hampir 3.000 notifikasi error. Error-error ini sebagian besar bukan logic bug yang serius, melainkan type incompatibility dan implicit any yang menyebar seperti virus.
Apa Itu Implicit Any yang Bikin Pusing?
Di JavaScript, kamu bisa menulis:
javascript
function processData(data) {
// ... logic
}Ketika kamu ubah ini menjadi .ts, tanpa konfigurasi yang ketat, TS akan berasumsi bahwa data adalah tipe any. Ini artinya, kamu kehilangan semua manfaat TS. Tapi, begitu kamu mengaktifkan noImplicitAny: true di tsconfig.json (yang wajib kalau mau serius), TSC akan langsung protes ke semua fungsi yang belum dideklarasikan tipenya. Ribuan fungsi. Ribuan error.
Inilah momen yang disebut "gila-gilaan" itu. Kami tahu, kami tidak bisa menyelesaikan 3.000 error dalam semalam. Kami butuh strategi perang.
Fase 2: Strategi Perang Dingin (Tips Migrasi yang Terstruktur)
Migrasi ini tidak bisa dilakukan secara big bang (mengubah semua sekaligus). Itu resep stres dan deployment yang gagal. Kami memutuskan untuk menggunakan pendekatan incremental (bertahap).
1. Mulai dengan Konfigurasi yang "Santai" Tapi Cerdas
Kesalahan terbesar developer saat migrasi adalah langsung menyalakan semua strict flags. Kami tidak melakukannya. Kami mulai dengan tsconfig.json yang memungkinkan kami bernapas:
json
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": false, // <-- Ini kuncinya di awal!
"skipLibCheck": true,
// Tambahkan ini agar bisa memproses JS/TS bersamaan
"allowJs": true,
"checkJs": false // Matikan pengecekan JSDoc di awal
}
}Dengan strict: false, kami bisa merubah .js ke .ts tanpa error instan. Kami kemudian mulai menyalakan flag satu per satu, modul per modul, setelah setiap bagian selesai diketik.
Tips Javapixa: Prioritaskan noImplicitAny dan strictNullChecks. Kedua flag ini memberikan value tertinggi dalam pencegahan bug, tapi juga yang paling banyak menghasilkan error. Jangan nyalakan sebelum 80% kode di modul tersebut memiliki type yang jelas.
2. Kunci Triage: Modul Utama Dulu, Baru Utility
Kami membagi 5.000 baris ini menjadi tiga kategori:
- Core Services/Logic (The Heart): Fungsi-fungsi yang diakses oleh hampir semua bagian aplikasi (misalnya, authentication, API handler).
- UI/View Components (The Face): Komponen React/Vue yang menerima props.
- Utility Functions (The Muscle): Fungsi helper kecil yang digunakan di sana-sini.
Kami mulai dari (1). Jika core services sudah memiliki type yang benar, maka bagian (2) dan (3) akan otomatis terpandu. Memperbaiki type di API handler secara langsung mengurangi error di 50 komponen UI yang mengonsumsinya.
3. Menaklukkan Dependencies Eksternal
Banyak kode lama kami menggunakan library pihak ketiga yang sudah usang atau library baru yang belum punya type bawaan. Ini menimbulkan error: Could not find a declaration file for module 'x'.
Solusinya terbagi dua: The Easy Way: Cari paket @types/nama-library. Ini adalah type definition* yang dibuat komunitas. Jika ada, instal saja. Selesai. The Hard Way: Jika @types tidak ada, kami harus membuat declaration file manual (.d.ts). Untuk 5.000 baris, kami hanya perlu membuat beberapa stub sederhana untuk library* yang paling sering digunakan, biasanya hanya mendeklarasikan: declare module 'nama-library';
Ini memang mengorbankan type safety untuk library tersebut, tapi memungkinkan kompilasi berhasil sementara kami fokus pada kode kami sendiri.
4. The Power of unknown vs. any
Di kode lama, banyak tempat kami tidak tahu data apa yang masuk (terutama dari request body atau third-party API). Dulu, solusinya adalah any.
Di TypeScript modern, any adalah jurang maut. Kami menggantinya dengan unknown.
typescript
// Dulu:
function handleAPI(response: any) { ... }Penggunaan unknown memaksa developer untuk melakukan pengecekan tipe (type narrowing) sebelum menggunakan data tersebut. Ini adalah pertahanan diri terbaik terhadap bug data yang tidak terduga.
Fase 3: Tantangan Teknis Lanjutan (The Real Deep Dive)
Setelah error implisit any dan dependency teratasi, kami masuk ke masalah yang lebih spesifik di 5.000 baris kode yang sudah berusia:
A. Legacy Classes dan this Context
Kode JS lama sangat suka menggunakan konstruktor class dan manipulasi this yang dinamis. Di TypeScript, context this harus sangat jelas, terutama dalam callback dan method yang dilempar ke komponen lain.
Solusi kami adalah menggunakan Arrow Functions sebanyak mungkin di dalam class untuk memastikan this selalu merujuk pada instance class yang benar, atau secara eksplisit menentukan tipe this dalam deklarasi fungsi.
B. Menggunakan Utility Types untuk Refactoring Cepat
Untuk objek yang sangat besar yang hanya butuh sedikit modifikasi, kami memanfaatkan Utility Types. Ini sangat mempercepat pekerjaan refactoring kami di Javapixa:
Partial: Ketika kami punya tipe User lengkap, tapi di fungsi update* kami hanya butuh sebagian data (opsional).
Pick: Untuk memilih hanya beberapa properti dari objek yang besar.Omit: Kebalikan dariPick, untuk mengecualikan properti tertentu.
Bayangkan kamu memiliki tipe 20 properti, dan kamu hanya perlu 3 di antaranya. Daripada mendefinisikan tipe baru, cukup: Pick. Lebih cepat, lebih bersih.
C. Integrasi dengan JSDoc (Jembatan Sementara)
Beberapa file JS yang terlalu kompleks kami putuskan untuk dibiarkan sementara waktu sebagai .js, tetapi kami menambahkan type checking minimal menggunakan JSDoc.
Dengan JSDoc, kami bisa memberikan anotasi tipe di file JavaScript, dan TSC bisa membacanya tanpa perlu mengubah ke .ts penuh. Ini adalah jembatan yang sangat efektif untuk manajemen risiko, memungkinkan kami memprioritaskan konversi file yang lebih kritikal terlebih dahulu.
Fase 4: Akhirnya Gini (The Payoff)
Proses migrasi 5.000 baris ini memakan waktu kurang lebih dua minggu kerja intensif. Apakah itu sepadan dengan 3.000 error yang harus kami hadapi? Jawaban kami, dan juga tim developer internal klien, adalah: YA, SANGAT.
Setelah semua type diatur, fitur yang dulunya butuh setengah hari untuk di-debug karena masalah undefined kini langsung terdeteksi di IDE (Visual Studio Code).
Beberapa perubahan nyata yang kami rasakan:
- Kecepatan Refactoring Naik 40%: Kami bisa mengubah struktur data inti tanpa takut merusak 10 bagian lain, karena TSC akan memberi tahu persis di mana perubahannya berdampak.
- Dokumentasi Otomatis: Tipe adalah dokumentasi. Developer baru yang melihat kode tidak perlu menebak-nebak tipe data yang masuk ke sebuah fungsi.
- Pengurangan Runtime Error: Bug fatal yang biasanya muncul seminggu setelah deployment karena data yang salah kini tertangkap saat kompilasi.
Kami di Javapixa Creative Studio tidak hanya fokus membuat aplikasi yang terlihat bagus, tapi juga aplikasi yang tahan banting dan maintainable. Migrasi ke TypeScript mungkin terasa menakutkan, terutama ketika kamu melihat ribuan notifikasi error di awal. Tapi percayalah, ini adalah rasa sakit sesaat yang akan memberikan ketenangan bertahun-tahun ke depan.
Jika kamu atau timmu sedang bergulat dengan codebase JavaScript yang sudah mulai ‘berantakan’ dan butuh tangan profesional untuk melakukan refactoring masif dan migrasi ke teknologi modern seperti TypeScript, jangan ragu untuk menghubungi kami. Kami sudah melewati badai 3.000 error ini, dan kami tahu cara mendarat dengan selamat. Membangun aplikasi yang scalable dan reliable adalah keahlian utama Javapixa Creative Studio.