Cái bẫy 'null reference' trong TypeScript và cách tránh

Phong

Cái bẫy 'null reference' trong TypeScript và cách tránh

Hồi mới qua TypeScript từ JavaScript, mình cũng từng nghĩ "à có type rồi thì khỏi sợ null". Thiệt tình là mình sai to, mấy bạn ơi. null với undefined là cái bẫy muôn thuở — type system chỉ check được ở compile time, còn runtime thì chuyện gì cũng có thể xảy ra.

Ảnh: Lukas Blazek — Pexels

Mình gặp hoài cái pattern kiểu này: data từ API về, mình .map() thẳng tay, xong runtime báo "Cannot read properties of undefined". Lỗi cơ bản mà thiệt tình ai cũng dính ít nhất vài lần. Giải pháp thì đơn giản — optional chaining (?.) với nullish coalescing (??) là best friend của mọi TypeScript dev.

Thay vì viết:

if (user && user.profile && user.profile.name) {
  console.log(user.profile.name);
}

Thì viết gọn:

console.log(user?.profile?.name ?? 'Khách');

Nhìn khác biệt nhỏ nhưng code đỡ rác thiệt nhiều. Optional chaining tự động kiểm tra từng level — nếu user undefined thì trả về undefined luôn, không crash. Nullish coalescing (??) thì khác với || ở chỗ: ?? chỉ fallback khi value là null hoặc undefined, chứ không fallback khi value là 0, false, hay '' (empty string). Cái này nhiều bạn mới dễ nhầm lắm.

Ảnh: ThisIsEngineering — Pexels

Một trick nữa mình hay xài là discriminated unions — thay vì để data lơ lửng kiểu T | null khắp nơi, mình dùng type kèm tag để biết chính xác trạng thái:

type Result<T> = 
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; message: string };

Cái này đặc biệt hữu ích khi xử lý async data. TypeScript tự động narrow type dựa trên status — gõ result.data chỉ khi đã check result.status === 'success', TypeScript không cho gọi lung tung.

Nói chung thì null reference là vấn đề muôn thuở của dev nào cũng gặp, nhưng với TypeScript, mấy trick trên giúp mình đỡ đau đầu thiệt nhiều. Mấy bạn có cách nào hay hơn hông? Chia sẻ với mình nha!