1 คะแนน โดย kwan03240324 2026-04-03 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

เมื่อดูโค้ดเบส TypeScript ไปเรื่อย ๆ มักจะเจอกรณีที่
ตัว implementation ของฟังก์ชันคืนค่าที่แคบกว่า แต่ return type ยังถูกปล่อยให้กว้างกว่าอยู่บ่อยครั้ง

ตัวอย่างเช่นโค้ดแบบนี้

type Status = "idle" | "loading" | "error";  
  
function getStatus(isLoading: boolean): Status {  
  if (isLoading) return "loading";  
  return "idle";  
}  

ในประกาศ type มี error รวมอยู่ด้วย แต่ implementation จริงคืนค่าแค่ idle และ loading เท่านั้น

โค้ดลักษณะนี้ถือว่าใช้ได้ในมุมมองของ TypeScript แต่ก็อาจนำไปสู่ปัญหาอย่าง
มีสมาชิกของ return type ที่ไม่ถูกใช้อีกแล้วหลงเหลืออยู่หลังการรีแฟกเตอร์ หรือมีการคงไว้ซึ่งการระบุ return type ที่กว้างกว่าตัว implementation

จากที่พบจริง เคสแบบนี้มักเกิดขึ้นในสถานการณ์อย่าง
• union member ที่หลงเหลือหลังการรีแฟกเตอร์
• การระบุ type แบบ manual ที่ไม่ตรงกับ implementation
• type annotation ที่ค่อนข้างหลวมซึ่ง AI สร้างขึ้น

จึงได้ลองทำ กฎ TypeScript ESLint แบบกำหนดเอง สำหรับตรวจจับ return type ที่ระบุกว้างกว่าการ implement ขึ้นมา

https://github.com/minseong0324/eslint-plugin-no-misleading-return-type

ตัวอย่างกรณีที่กฎนี้ครอบคลุม เช่น
• สมาชิกบางส่วนของ union type ไม่ได้ถูกคืนค่าอีกต่อไป
• ระบุเป็น string แต่ implementation จริงคืนค่าแค่ literal union ที่แคบกว่า
• ระบุเป็น Record<string, string> แต่ implementation จริงคืนค่าเป็นอ็อบเจ็กต์ as const ที่มี key เฉพาะ
• เป็นต้น

เจตนาไม่ใช่ “เลิกเขียน return type กันเถอะ” แต่เป็นการ
เพิ่ม guardrail ที่ทำให้ต้องกลับมาดูอีกครั้งว่า return type ที่ระบุไว้ตรงกับ implementation จริงหรือไม่

ยังมีเคสซับซ้อนบางอย่างที่ยังไม่รองรับ และยังมีจุดที่ต้องปรับปรุงอยู่ แต่ในยุค AI ที่ความเร็วในการสร้างโค้ดสูงขึ้นเรื่อย ๆ ก็รู้สึกว่าจำเป็นต้องมีตัวช่วยสำหรับจับ type drift ลักษณะนี้แบบอัตโนมัติมากขึ้น จึงได้ทำสิ่งนี้ขึ้นมา

ยินดีรับฟีดแบ็กครับ

1 ความคิดเห็น

 
kwan03240324 2026-04-03

สิ่งที่อยากรู้เป็นพิเศษคือ ควรมองถึงขอบเขตไหนว่าเป็นชนิดคืนค่าที่กว้างขึ้นโดยตั้งใจ และตั้งแต่จุดไหนจึงควรมองว่าเป็นชนิดคืนค่าที่ไม่สอดคล้องกับการนำไปใช้จริง