ค้นหาเว็บไซต์

ทำไม 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
};

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

บทความที่เกี่ยวข้อง