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

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' };

เป้าหมายคือการมีคุณสมบัติร่วมบางประการ

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