Aplikasi yang dibangun dengan TypeScript strict mode yang diaktifkan mengalami sekitar 40% lebih sedikit bug terkait tipe yang mencapai produksi. Saya telah mengaktifkan strict mode di setiap proyek yang saya sentuh selama dua tahun terakhir, termasuk selama migrasi proyek warisan. Rasa sakit awal — dinding error tipe saat Anda pertama kali membalik sakelar — nyata. Tapi apa yang strict mode ungkap lebih berharga dari fitur apa pun yang bisa Anda bangun selama jendela refaktor tersebut.
Flag strict di tsconfig.json adalah singkatan untuk sekelompok pemeriksaan individual: strictNullChecks, noImplicitAny, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, dan noImplicitThis. Masing-masing menangani kategori bug runtime yang berbeda.
Sebelum strictNullChecks, TypeScript membiarkan string | null | undefined semuanya diperlakukan sebagai string. Beginilah Anda mendapatkan Cannot read properties of null (reading 'name') di produksi — error yang menyumbang lebih banyak insiden produksi dari penyebab tunggal lainnya. Dengan strictNullChecks diaktifkan, TypeScript memaksa Anda menangani null dan undefined secara eksplisit. user?.name alih-alih user.name.
"strict": true ──► enables all of these:
│
├── strictNullChecks ← most important
│ Without: let x: string = null // OK (dangerous)
│ With: let x: string = null // Error: Type 'null' not assignable
│
├── noImplicitAny ← second most important
│ Without: function foo(x) { ... } // x is implicitly 'any'
│ With: function foo(x: string) // must be explicit
│
├── strictFunctionTypes ← function parameter safety
├── strictBindCallApply ← bind/call/apply type checking
├── strictPropertyInitialization ← class properties must init
└── noImplicitThis ← 'this' must be typed
Real bugs caught by strict mode in production Next.js apps:
──────────────────────────────────────────────────────────
// Prisma findUnique returns T | null
const user = await prisma.user.findUnique({ where: { id } })
user.name // 🔴 Error: Object is possibly 'null' — forces you to check
// Array.find returns T | undefined
const item = cart.items.find(i => i.id === id)
item.quantity // 🔴 Error: Object is possibly 'undefined'
// API response without explicit typing
const data = await fetch(url).then(r => r.json())
// With noImplicitAny + ts-reset: data is unknown, not any
// Forces you to validate before useDari mengaktifkan strict mode pada basis kode NestJS + Next.js ERP warisan dengan 15.000 baris: jangan aktifkan semua flag strict sekaligus. Aktifkan strictNullChecks terlebih dahulu (ia memiliki rasio sinyal-ke-noise tertinggi untuk bug nyata), perbaiki, lalu aktifkan noImplicitAny, lalu sisanya. Pendekatan bertahap ini memungkinkan Anda mengirimkan migrasi secara bertahap tanpa penulisan ulang besar-besaran.
Dalam aplikasi Next.js berbasis Prisma, tangkapan paling umum adalah: (1) findUnique() mengembalikan T | null — tanpa strictNullChecks, Anda akan mengakses hasilnya langsung dan crash saat catatan tidak ada. (2) Array.find() mengembalikan T | undefined. (3) Optional chaining pada respons API. (4) Inisialisasi properti kelas — strict mode menangkap layanan NestJS di mana dependensi tidak diinjeksikan dengan benar.
// tsconfig.json — enable strict
{
"compilerOptions": {
"strict": true,
"skipLibCheck": true, // skip during migration
"noUncheckedIndexedAccess": true, // bonus: arr[0] is T | undefined
"exactOptionalPropertyTypes": true // bonus: stricter optional props
}
}
// NestJS tsconfig — extra config needed for DI
{
"compilerOptions": {
"strict": true,
"strictPropertyInitialization": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
}
// NestJS: handle strict property initialization with !
@Injectable()
export class UsersService {
@InjectRepository(User)
private readonly userRepo!: Repository<User> // ! = Definite Assignment Assertion
}
// Prisma + strict mode: always handle null
const user = await prisma.user.findUnique({ where: { id } })
if (!user) throw new NotFoundException(`User ${id} not found`)
// After the check, user is narrowed to User (not User | null)
console.log(user.name) // ✅ TypeScript knows this is safe
// ts-reset for better built-in types (optional but recommended)
// npm install --save-dev @total-typescript/ts-reset
// Create reset.d.ts:
import "@total-typescript/ts-reset"
// Now: fetch().json() returns unknown (not any)
// Array.includes() accepts broader types correctly
// JSON.parse() returns unknown (not any)Beberapa library lama memiliki paket @types yang tidak sepenuhnya kompatibel dengan strict mode — mereka akan mengembalikan any dari fungsi yang biasanya ditangkap strict mode. Solusinya: tulis fungsi wrapper yang sempit yang menambahkan tipe yang diharapkan strict mode. Untuk klien API, gunakan Zod untuk mengurai dan mengetik respons API di batas — ini memberi Anda keamanan tipe runtime DAN memenuhi analisis statis strict mode.
Mengaktifkan strict mode pada basis kode yang ada yang besar akan menghasilkan ratusan atau ribuan error — jangan biarkan ini menghalangi Anda. Gunakan pendekatan yang direkomendasikan tim TypeScript: aktifkan strict di tsconfig.json tapi tambahkan 'skipLibCheck: true' sementara, dan gunakan @ts-expect-error secara jarang untuk kasus yang akan Anda tangani nanti. Lacak jumlah error Anda sebagai metrik. Saya mengurangi satu proyek warisan dari 847 error strict menjadi 0 selama tiga minggu sambil mengirimkan fitur secara paralel.
Strict mode membuat compiler TypeScript bekerja lebih keras — pemeriksaan tipe lebih menyeluruh. Waktu build meningkat secara moderat (5-15% biasanya). Sebagai gantinya, Anda mendapatkan autocomplete IDE yang lebih baik (IntelliSense lebih akurat dengan tipe strict), jump-to-definition yang lebih baik, dan dukungan refactoring yang lebih baik. Peningkatan pengalaman pengembang dari IntelliSense yang lebih baik saja membenarkan peningkatan waktu kompilasi.
strict: true ada di tsconfig.json setiap proyek yang saya mulai. Tanpa pengecualian. Untuk proyek NestJS, saya mengaktifkannya secara eksplisit di tsconfig.json bersama strictPropertyInitialization: true (yang tidak diaktifkan NestJS secara default karena dependency injection membingungkan pemeriksa inisialisasi properti — gunakan Definite Assignment Assertion ! pada properti yang diinjeksikan).
TypeScript strict mode adalah baseline, bukan langit-langit. Lapisi di atasnya: ESLint dengan aturan @typescript-eslint/recommended (terutama no-explicit-any dan no-non-null-assertion), Zod untuk validasi runtime di batas API, dan ts-reset untuk koreksi tipe global. Stack ini memberi Anda keamanan tipe di compile-time + lint-time + runtime — tiga lapisan perlindungan terhadap ketidakcocokan bentuk.