typescript - การรวมประเภทไม่ได้ตรวจสอบคุณสมบัติเกิน
ลองจินตนาการว่าฉันมีวัตถุที่มีคุณสมบัติ A และ B หรือ C เช่น:
const temp = {
A: 1,
B: 2,
}
หรือ
const temp = {
C: 3,
}
และโดยสัญชาตญาณฉันมองประเภทนี้ว่า:
type T = {A: number, B: number} | {C: number};
const valid: T = {A: 1, B: 2};
const alsoValid: T = {C: 3};
// Should complain but it does not
const invalid: T = {A: 1, B: 2, C: 3};
// Also should complain
const alsoInvalid: T = {A:1, C: 3};
แต่ TS จัดการประเภทดังกล่าวเป็น {A?: number, B?: number, C?: number} และโดยพื้นฐานแล้ว | ทำให้ฟิลด์เป็นทางเลือก แต่ฉันต้องการให้ TS แจ้งข้อผิดพลาดเกี่ยวกับประเภทที่ไม่สอดคล้องกันเมื่อฉันเพิ่มคุณสมบัติ C ให้กับ A และ B
ฉันจะสามารถบรรลุประเภทที่ต้องการได้อย่างไร?
คำตอบ #1
นี่เป็นนิสัยประหลาดเล็กน้อยในการทำงานของยูเนียนควบคู่กับการตรวจสอบคุณสมบัติที่เกินกำหนด {A:1, C: 3} จริงๆ แล้วเข้ากันได้กับ {C: number} ยกเว้นการตรวจสอบคุณสมบัติที่เกินกำหนด:
const o = {A:1, C: 3};
const ok: {C: number} = o; // No direct literal assignment, no excess property checks
const nok: {C: number} = { A:1, C: 3}; // Excess property checks kick in
ลิงก์สนามเด็กเล่น
และลักษณะเฉพาะของการตรวจสอบคุณสมบัติเกินคือ สำหรับ union มันอนุญาตให้คุณสมบัติใด ๆ จาก ส่วนประกอบ ของ union ใด ๆ ปรากฏอยู่ใน object literal ที่ถูกกำหนดค่า
คุณอาจได้รับข้อผิดพลาดหากสมาชิกของยูเนียนไม่สามารถใช้งานร่วมกันได้
type T = {A: number, B: number} | {C: number, A?: undefined, B?: undefined };
const valid: T = {A: 1, B: 2};
const alsoValid: T = {C: 3};
// Error
const invalid: T = {A: 1, B: 2, C: 3};
//Error
const alsoInvalid: T = {A:1, C: 3};
ลิงก์สนามเด็กเล่น
คุณยังสามารถใช้ StrictUnion จากที่นี่ได้หากยูเนียนมีสมาชิกจำนวนมาก
type UnionKeys<T> = T extends T ? keyof T : never;
type StrictUnionHelper<T, TAll> = T extends any ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
type StrictUnion<T> = StrictUnionHelper<T, T>
type T = StrictUnion<{A: number, B: number} | {C: number }>;
const valid: T = {A: 1, B: 2};
const alsoValid: T = {C: 3};
// Error
const invalid: T = {A: 1, B: 2, C: 3};
//Error
const alsoInvalid: T = {A:1, C: 3};
ลิงก์สนามเด็กเล่น
คำตอบ #2
ฉันแค่ชอบเพิ่ม type ของยูเนียนเสมอ ตัวอย่างเช่น:
type T = { A: number, B: number, type: 'ONE' } | { C: number, type: 'TWO' };
const valid: T = { A: 1, B: 2, type: 'ONE' };
const alsoValid: T = { C: 3, type: 'TWO' };
// Should complain but it does not
const invalid: T = { A: 1, B: 2, C: 3, type: "ONE" };
// Also should complain
const alsoInvalid: T = { A: 1, C: 3, type: 'TWO' };
เป้าหมายคือการมีคุณสมบัติร่วมบางประการ
