Bikin Proyek Lebih Stabil dengan TypeScript Strict Mode Ini Tiga Hal Wajib Kamu Atur

Bikin Proyek Lebih Stabil dengan TypeScript Strict Mode Ini Tiga Hal Wajib Kamu Atur
Photo by Brett Jordan/Unsplash

Kalau kamu sering ngoprek proyek JavaScript, apalagi yang skalanya sudah mulai membesar, kamu pasti tahu rasanya terjebak dalam bug aneh di runtime yang bikin kepala pusing tujuh keliling. Kode yang kelihatannya aman-aman saja, tiba-tiba "meledak" di tangan user.

Nah, ini dia alasan kenapa jutaan developer (termasuk tim ahli di Javapixa Creative Studio) sangat mengandalkan TypeScript. Tapi sekadar pakai TypeScript saja tidak cukup, Bro. Kamu harus memaksa dia bekerja keras. Caranya? Mengaktifkan Strict Mode.

Strict Mode ini bukan cuma fitur keren-kerenan; ini adalah pagar pengaman yang akan membuat proyek kamu jauh lebih stabil, mudah di-refactor, dan siap menghadapi masa depan, entah itu untuk pengembangan website e-commerce skala besar atau mobile application yang kompleks. Di Javapixa, kami selalu memastikan setiap klien mendapatkan solusi aplikasi yang bukan hanya cantik di luar, tapi juga kokoh di dalamnya. Dan kekokohan itu dimulai dari konfigurasi tsconfig.json yang ketat.

Yuk, kita bahas tiga pengaturan wajib yang harus kamu aktifkan —meskipun awalnya terasa ribet— demi mendapatkan kualitas kode premium ala Javapixa.

*

Mengapa Strict Mode Itu Wajib? Bukan Opsional

Sebelum kita gas ke tiga pengaturan intinya, mari kita luruskan dulu. Saat kamu inisiasi proyek TypeScript baru, compiler biasanya datang dengan konfigurasi yang cukup "longgar". TypeScript ini baik hati, dia berusaha keras untuk mengompilasi kode kamu meskipun ada beberapa ketidakpastian (misalnya, variabel yang tidak jelas tipenya).

Sikap baik hati ini justru yang berbahaya. Kenapa? Karena dia membiarkan potensi runtime error lolos dari proses kompilasi. Kamu mungkin merasa nyaman karena kode kamu langsung jalan, tapi saat datanya berubah atau user menginput sesuatu yang tidak terduga, BUM! Aplikasi kamu crash.

Strict Mode (sebenarnya diwakili oleh flag strict: true yang mengaktifkan semua opsi ketat) adalah cara kita bilang ke TypeScript, "Hei, jangan baik-baik banget, dong! Aku mau kamu cerewet. Kalau ada potensi error, langsung teriak!"

Meskipun strict: true sudah mencakup semuanya, memahami tiga komponen inti di bawah ini akan membuat kamu jadi developer yang lebih sadar dan mampu mendiagnosis masalah konfigurasi dengan cepat.

*

1. Pillar Stabilitas Pertama: noImplicitAny (Katrol Tipe Data)

Bayangkan kamu sedang membangun aplikasi dengan ribuan baris kode, dan di dalamnya terdapat fungsi-fungsi yang menerima data, tapi kamu lupa mendefinisikan tipe datanya.

Secara default, jika TypeScript tidak bisa menebak tipe data dari suatu variabel atau parameter fungsi, dia akan diam-diam memberikan tipe any.

typescript
// Tanpa noImplicitAny: Aman-aman saja
function prosesData(data) {
  return data.toUpperCase(); // Oops, kalau 'data' adalah angka?
}

Jika data ternyata adalah angka, kode di atas akan lolos kompilasi (karena any menerima segalanya), tapi akan hancur ketika dijalankan (karena angka tidak punya metode toUpperCase).

Inilah mengapa noImplicitAny sangat krusial.

Apa yang Dilakukannya?

Ketika noImplicitAny: true diaktifkan, TypeScript akan langsung protes keras (memberikan error kompilasi) jika ada variabel atau parameter fungsi yang secara implisit (diam-diam) diberi tipe any. Kamu dipaksa untuk mendefinisikan tipe data tersebut secara eksplisit.

typescript
// Dengan noImplicitAny: Error!
function prosesData(data: string) { // Dipaksa mendefinisikan
  return data.toUpperCase(); 
}

Mengapa Ini Wajib? (Visi Jangka Panjang Javapixa)

  1. Mencegah Runtime Crash: Ini adalah perlindungan utama dari crash yang disebabkan oleh tipe data yang salah. Jika kamu tahu data harus berupa string, maka aplikasi kamu akan stabil, Bro.
  2. Dokumentasi Otomatis: Ketika kamu mendefinisikan tipe data, kode kamu secara otomatis menjadi dokumentasi. Developer lain (atau diri kamu sendiri enam bulan kemudian) tidak perlu menebak-nebak input apa yang dibutuhkan fungsi tersebut.
  3. Refactoring Jadi Gampang: Ketika skala proyek membesar (seperti proyek-proyek website korporat atau custom application yang dikerjakan oleh Javapixa), kamu pasti sering melakukan refactoring. Dengan tipe yang jelas, proses refactoring jauh lebih aman karena compiler akan memberitahu kamu semua tempat yang terpengaruh oleh perubahan tipe data.

Mengaktifkan noImplicitAny memang butuh usaha lebih di awal, tapi ini adalah investasi terbesar untuk kesehatan jangka panjang proyek kamu. Jangan pernah kompromi di sini.

*

2. Pillar Stabilitas Kedua: strictNullChecks (Memusnahkan The Billion Dollar Mistake)

Jika noImplicitAny adalah tentang memastikan tipe data kamu ada, maka strictNullChecks adalah tentang memastikan tipe data kamu berisi.

Developer veteran pasti tahu pepatah tentang Null Reference Error. Tony Hoare, penemu konsep null, pernah menyebutnya sebagai "kesalahan bernilai satu miliar dolar" karena kerugian waktu dan uang yang dihabiskannya untuk memperbaiki bug yang disebabkan oleh nilai null atau undefined yang muncul di waktu yang tidak terduga.

Secara default di TypeScript, null dan undefined dianggap valid untuk hampir semua tipe data. Misalnya, variabel bertipe string secara teknis boleh menampung null atau undefined.

typescript
let username: string = 'Budi';
username = null; // Default TypeScript: OK!
console.log(username.toLowerCase()); // Crash di runtime!

Apa yang Dilakukannya?

Saat kamu mengaktifkan strictNullChecks: true, TypeScript mengubah perilakunya secara radikal. Dia akan menganggap null dan undefined hanya valid jika kamu secara eksplisit menyertakannya dalam definisimu (menggunakan union types).

Artinya, jika kamu mendefinisikan let username: string, maka username hanya boleh berisi string, tidak boleh null atau undefined.

typescript
// Dengan strictNullChecks: Error di baris kedua!
let username: string = 'Budi';
username = null; // TypeScript Error: 'null' tidak bisa ditetapkan ke 'string'.

Mengapa Ini Sangat Penting di Dunia Nyata?

Dalam pengembangan aplikasi modern, terutama yang mengandalkan data dari API (misalnya, mengambil data profil user dari backend), data sering kali bersifat opsional. Data yang hilang atau belum terisi akan dikirim sebagai null.

  1. Wajib Cek Kondisi: strictNullChecks memaksa kita (sebagai developer) untuk selalu bertanggung jawab atas data yang mungkin kosong. Kamu harus menggunakan conditional checks (if (data)) atau menggunakan optional chaining (?.) sebelum mengakses properti. Ini mencegah crash saat data API belum terisi atau gagal dimuat.
  2. Kejelasan Desain: Saat tim Javapixa merancang struktur data, kami selalu mendefinisikan dengan jelas, mana data yang pasti ada dan mana data yang opsional. Dengan strictNullChecks, kejelasan desain ini tercermin langsung di kode. Jika sebuah properti boleh null, kita definisikan: email?: string | null;.
  3. Mengurangi Debugging Tengah Malam: Sebagian besar bug yang paling sulit dilacak dalam JavaScript non-strict mode adalah Null Pointer Exception. Dengan Strict Null Checks, masalah ini terdeteksi saat kompilasi, jauh sebelum kode itu sempat masuk ke tangan user.

Pengaturan ini mungkin yang paling "menyiksa" bagi developer yang baru pindah dari JavaScript murni, karena tiba-tiba semua kode mereka dipenuhi tanda seru merah. Tapi percaya deh, rasa sakit di awal ini akan menghasilkan proyek yang jauh lebih andal dan tahan banting.

*

3. Pillar Stabilitas Ketiga: strictPropertyInitialization (Kejelasan Properti Kelas)

Bagi kamu yang bekerja dengan framework berbasis kelas (seperti NestJS untuk backend, atau Angular, bahkan React dengan class components), properti di dalam kelas adalah inti dari arsitektur.

Seringkali, properti di dalam kelas dideklarasikan, namun nilainya baru diisi di dalam constructor atau melalui metode asinkron (misalnya, di React lifecycle method componentDidMount).

Secara default (tanpa Strict Mode), kamu bisa mendeklarasikan properti tanpa memberikan nilai awal di kelas.

typescript
class Pengguna {
  nama: string; // TS default: OK, akan diisi nanti
  
  constructor(namaInput: string) {
    this.nama = namaInput; // Diharapkan diisi di sini
  }
}

Masalah muncul jika kamu lupa mengisi properti tersebut di constructor, atau jika alur logika kamu membuat properti tersebut tidak terisi. Ketika properti tersebut diakses, hasilnya adalah undefined.

Apa yang Dilakukannya?

strictPropertyInitialization: true mengharuskan setiap properti kelas (yang bukan optional atau nullable) untuk diinisialisasi secara langsung di baris deklarasinya, atau di dalam constructor.

Jika kamu mendeklarasikan properti tanpa nilai awal dan tidak mengisinya di constructor, TypeScript akan mengeluarkan error kompilasi.

Ini adalah bentuk proteksi yang sangat spesifik tapi sangat penting untuk arsitektur berbasis object-oriented programming (OOP).

Menghindari "Lupa Memberi Nilai"

Dalam pengembangan aplikasi skala besar, kelas seringkali memiliki banyak properti. Pengaturan ini memastikan:

  1. Konsistensi Objek: Setiap instance objek yang dibuat selalu berada dalam keadaan yang valid, karena semua properti yang wajib sudah terisi sejak objek itu lahir (saat constructor dijalankan).
  2. Penanganan Asinkron: Kalau kamu punya properti yang memang tidak mungkin diisi di constructor (misalnya, data user yang diambil dari API setelah 5 detik), kamu harus secara eksplisit memberitahu TypeScript bahwa properti itu mungkin undefined atau null di awal.

typescript
    class DataService {
      dataApi: string | undefined; // Dinyatakan mungkin undefined

Atau, jika kamu yakin properti itu pasti akan diisi (meski terlambat) dan kamu tidak ingin repot dengan undefined check setiap saat (biasanya ini digunakan dengan hati-hati pada framework yang menjamin inisialisasi), kamu bisa menggunakan definite assignment assertion (!).

typescript
    class DataService {
      dataApi!: string; // Tanda seru menyatakan: "Aku yakin ini akan diisi!"
      
      // ...
    }

Namun, penggunaan ! harus sangat hati-hati. Standar Javapixa adalah sebisa mungkin menggunakan tipe | undefined untuk properti yang tidak langsung diinisialisasi, karena lebih aman dan jujur tentang kondisi properti tersebut.

*

Implementasi di Javapixa Creative Studio: Mengaktifkan Sang Jenderal

Idealnya, daripada mengaktifkan ketiga opsi di atas satu per satu, kamu cukup mengaktifkan sang jenderal utamanya: strict: true.

json
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "rootDir": "./src",
    "outDir": "./dist",
    
    // 🔥 Inilah intinya!
    "strict": true, 
    
    // Ketika "strict: true" diaktifkan, secara otomatis ini semua jadi TRUE:
    // "noImplicitAny": true,
    // "strictNullChecks": true,
    // "strictFunctionTypes": true,
    // "strictPropertyInitialization": true,
    // "noImplicitThis": true,
    // "alwaysStrict": true,
  }
}

Dengan mengaktifkan strict: true, kamu mendapatkan full package stabilitas dan kehati-hatian yang dibutuhkan dalam proyek profesional.

Di awal, mungkin kamu akan merasa frustrasi melihat banyak error kompilasi, terutama jika kamu memindahkan kode JS lama ke TS. Tapi anggaplah error ini sebagai hadiah. Itu artinya, TypeScript baru saja menyelamatkan kamu dari potensi bug yang bisa menghancurkan pengalaman pengguna kamu di masa depan.

Saat kamu membangun web application atau custom mobile app bersama Javapixa Creative Studio, kamu tidak hanya mendapatkan desain yang memukau, tetapi juga arsitektur kode yang teruji dan stabil. Kami percaya bahwa kualitas kode yang ketat (berkat Strict Mode dan standar pengkodean modern lainnya) adalah kunci untuk memastikan aplikasi klien kami tetap perform tinggi dan mudah di-maintenance selama bertahun-tahun.

Jadi, tunggu apa lagi? Buka tsconfig.json proyek kamu sekarang, atur strict: true, dan saksikan proyek kamu naik tingkat menjadi kode yang profesional dan bebas bug tersembunyi. Ribet di awal, nyaman seumur proyek! Gaskeun!