ทำไม Typescript จึงอนุญาตให้ `{a: 1, b: 2}` ถูกกำหนดค่าให้กับประเภท `{a: any} | {b: any}`?
พิจารณาโค้ดนี้:
let foo: {a: any} | {b: any} = {a: 1, b: 2};
ฉันคาดว่า TypeScript จะปฏิเสธโค้ดนี้ เนื่องจาก union type นี้หมายถึงจะเป็นประเภทแรกหรือประเภทที่สอง และค่าดังกล่าวไม่สามารถกำหนดให้กับประเภทใดก็ได้ ดังนั้นการตรวจสอบประเภทควรปฏิเสธมัน แต่ในความเป็นจริงมันกลับผ่าน ทำไมถึงเป็นแบบนั้น?
(สำหรับพื้นหลัง ประเภทที่กล่าวถึงข้างต้นถูกออกแบบมาให้เป็น "คุณสมบัตินี้หรือคุณสมบัตินั้น แต่ไม่ใช่ทั้งสองประเภท" ดู Typescript Interface - เป็นไปได้หรือไม่ที่จะทำให้คุณสมบัติ "อย่างใดอย่างหนึ่ง" เป็นสิ่งที่ต้องการ?)
คำตอบ #1
ตามโพสต์บล็อกที่แนะนำการตรวจสอบคุณสมบัติเกินของ union ใน TypeScript 3.5 TypeScript จะตรวจสอบว่ามันเป็นของ อย่างน้อยหนึ่งประเภท:
ใน TypeScript 3.4 และเวอร์ชันก่อนหน้า มีการอนุญาตคุณสมบัติเกินบางอย่างในสถานการณ์ที่จริง ๆ แล้วไม่ควรเกิดขึ้น ตัวอย่างเช่น TypeScript 3.4 อนุญาตคุณสมบัติ name ที่ไม่ถูกต้องใน object literal แม้ว่าประเภทของมันจะไม่ตรงกันระหว่าง Point และ Label
type Point = { x: number; y: number; }; type Label = { name: string; }; const thing: Point | Label = { x: 0, y: 0, name: true // uh-oh! };ก่อนหน้านี้ สหภาพที่ไม่ได้ถูกจัดประเภทจะไม่ทำการตรวจสอบคุณสมบัติเกินของสมาชิก และผลลัพธ์คือ คุณสมบัติชื่อที่พิมพ์ผิดได้หลุดไป
ใน TypeScript 3.5 ตัวตรวจสอบประเภทอย่างน้อยก็ยืนยันว่าคุณสมบัติทั้งหมดที่ให้มาจะต้องเป็นของสมาชิกยูเนียนบางตัวและมีประเภทที่เหมาะสม ซึ่งหมายความว่าตัวอย่างข้างต้นจะแจ้งข้อผิดพลาดอย่างถูกต้อง
โพสต์บล็อกได้อธิบายโดยตรงว่าการทับซ้อนเป็นสิ่งที่ถูกต้อง:
โปรดทราบว่าการซ้อนทับบางส่วนยังคงอนุญาตได้ตราบเท่าที่ประเภทของทรัพย์สินถูกต้อง
const pl: Point | Label = { x: 0, y: 0, name: "origin" // okay };
จากวลี "คุณสมบัติทั้งหมดที่ให้มานั้นเป็นของ สมาชิกยูเนียนบางตัว และมีประเภทที่เหมาะสม" ดูเหมือนว่าตัวตรวจสอบคุณสมบัติเกินนั้นไม่สามารถพิจารณาคุณสมบัติเหล่านั้นว่าเป็นแบบที่ตัดกันได้
