วันนี้ได้ลองให้ Sonarqube scan ดูแล้วเจอ warning Prefer using nullish coalescing operator (??=) instead of an assignment expression, as it is simpler to read.

โดยเฉพาะตัวนี้ ??= เป็นตัวที่ยังไม่เคยใช้เลย

เอามาเขียนสรุปไว้เหมือนเดิม


ก่อนอื่นเราต้อง เข้าใจ ?? กับ || กันก่อน

ใน JavaScript || เป็นตัวดำเนินการ OR ตรรกะ ซึ่งจะคืนค่า true ถ้ามีค่าใดค่าหนึ่งเป็นจริง

ในขณะที่ ?? เป็นตัวดำเนินการ nullish coalescing ซึ่งจะคืนค่าทางขวาหากค่าทางซ้ายเป็น null หรือ undefined

กล่าว คือ ...

|| (OR ตรรกะ)

จะประเมินค่าทางซ้ายก่อน หากค่าทางซ้ายเป็น truthy (เช่น ไม่ใช่ null, undefined, 0, '', NaN, false) จะคืนค่าทางซ้ายทันที หากค่าทางซ้ายเป็น falsy จะประเมินค่าทางขวา และคืนค่าทางขวา

console.log(null || "ค่าเริ่มต้น"); // Output: ค่าเริ่มต้น
console.log(true || "ค่าเริ่มต้น"); // Output: true

ตัวอย่าง ||

?? (Nullish Coalescing)

จะประเมินค่าทางซ้ายก่อน หากค่าทางซ้ายเป็น null หรือ undefined จะคืนค่าทางขวา หากค่าทางซ้ายไม่ใช่ null หรือ undefined จะคืนค่าทางซ้ายทันที.

console.log(null ?? "ค่าเริ่มต้น"); // Output: ค่าเริ่มต้น
console.log(0 ?? "ค่าเริ่มต้น"); // Output: 0

ตัวอย่าง ??

ประโยชน์ของ ?? คือ

  1. ปลอดภัยกว่า - ไม่ coalesce กับค่า falsy อื่น ๆ
  2. สั้นกว่า - ไม่ต้องเขียน conditional ยาว ๆ
  3. ชัดเจนกว่า - แสดงเจตนาที่ต้องการจัดการ null/undefined เท่านั้น
  4. ลดข้อผิดพลาด - หลีกเลี่ยงการ coalesce ที่ไม่ต้องการ

ความแตกต่างระหว่าง ?? และ ||

ทีนี้เรามาดูข้อแตกต่างกันระหว่าง 2 ตัวนี้กัน โดยจะเน้นไปที่ ค่า falsy ใน JavaScript ได้แก่ false, 0, "", null, undefined, NaN

Logical OR (||)

จะไม่ค่อยปลอดภัย เพราะมันจะ coalesce กับค่า falsy ทั้งหมด

const result1 = value || "default"

Nullish Coalescing (??)

จะปลอดภัยกว่า เพราะมันจะ coalesce เฉพาะ null และ undefined เท่านั้น

const result2 = value ?? "default"

มาดูตัวอย่างกัน

ตัวอย่างปัญหาที่เกิดขึ้น

// ❌ ปัญหาเมื่อใช้ ||
function getPort(port: number | null) {
  return port || 3000  // ถ้า port = 0 จะได้ 3000 (ผิด!)
}

getPort(0)     // ได้ 3000 แทนที่จะเป็น 0
getPort(null)  // ได้ 3000 (ถูก)

// ✅ แก้ไขด้วย ??
function getPort(port: number | null) {
  return port ?? 3000  // ถ้า port = 0 จะได้ 0 (ถูก!)
}

getPort(0)     // ได้ 0 (ถูก)
getPort(null)  // ได้ 3000 (ถูก)

ตัวอย่างการใช้งานจริง

// ❌ ไม่ปลอดภัย
const username = user.name || "Anonymous"        // ถ้า name = "" จะได้ "Anonymous"
const count = items.length || 0                  // ถ้า length = 0 จะได้ 0 (ซ้ำซ้อน)
const isEnabled = config.enabled || false       // ถ้า enabled = false จะได้ false (ซ้ำซ้อน)

// ✅ ปลอดภัยกว่า
const username = user.name ?? "Anonymous"       // เฉพาะ null/undefined เท่านั้น
const count = items.length ?? 0                 // เฉพาะ null/undefined เท่านั้น
const isEnabled = config.enabled ?? false      // เฉพาะ null/undefined เท่านั้น

การแทนที่ Conditional Expressions

// ❌ แบบเก่า - ยาวและซับซ้อน
const result = value !== null && value !== undefined ? value : "default"

// ✅ แบบใหม่ - สั้นและชัดเจน
const result = value ?? "default"

และอันสุดท้าย การใช้งาน ??=

let result = null

result ??= "default"