typescript อนุมานว่าฟิลด์นั้นเป็นความจริง (ไม่สามารถไม่ได้กำหนด) โดยไม่มีตัวป้องกันประเภทที่ผู้ใช้กำหนด

type Item = {
    left?: { photoSrc: string };
};

type ItemRequired = {
    left: { photoSrc: string };
};

const item: Item = {} as any;

if (item.left) {
    const itemRequired: ItemRequired = item; // fails. Typescript still says left may be undefined
    // I'd like Typescript to know that field left is truthy
}

ฉันรู้เกี่ยวกับการ์ดประเภทที่ผู้ใช้กำหนด เช่น.

function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

คำถามของฉัน:

  1. เหตุใด Typescript จึงไม่สามารถอนุมานได้ว่า left ไม่สามารถไม่ได้กำหนดได้
  2. นั่นหมายความว่าฉันต้องสร้างฟังก์ชันป้องกันประเภทสำหรับรูปแบบทุกประเภทที่ฉันต้องตรวจสอบใช่หรือไม่ ไม่มีวิธีที่ง่ายกว่านี้เหรอ? เช่น. ฉันคาดหวังเมื่ออยู่ในขอบเขตของการตรวจสอบ if ที่พิสูจน์ว่าฟิลด์ left ไม่สามารถไม่ได้กำหนดได้ ฉันคาดหวังว่า Typescript จะรู้สิ่งนั้น

ดูเหมือนว่าจะเป็นกรณีที่พบบ่อยมาก แต่ฉันไม่พบคำตอบ โปรดขออภัยหากมี


person ZenVentzi    schedule 31.05.2020    source แหล่งที่มา


คำตอบ (2)


เพื่อตอบคำถามของคุณ:

ฉันสันนิษฐานว่าเพราะ Typescript กำลังทำการเปรียบเทียบระหว่างสองประเภท: Item และ ItemRequired แทนที่จะเป็นสิ่งที่คุณต้องการซึ่งก็คือ { left:{ photoSrc:string } }

Typescript มักจะสามารถระบุได้ว่าส่วนใดของ union ประเภทที่คุณใช้ ไม่มี type guards แต่ก็ยังไม่สมบูรณ์แบบนัก มันขึ้นอยู่กับสถานการณ์ว่าอันไหนจะใช้ได้และไม่ได้ผล มีสถานการณ์ที่เป็นไปได้มากมาย

หลายๆ ครั้งผู้คนต้องการหลีกหนีโดยไม่มี Type Guard และนั่นก็เข้าใจได้ แต่บ่อยครั้งที่ดูเหมือนเป็นโค้ดเพิ่มเติมที่ไม่จำเป็น แต่มันถูกออกแบบมาสำหรับสถานการณ์ที่แน่นอนนี้จริงๆ:

const itemIsItemRequired = (item: Item): item is ItemRequired =>
  item.left !== undefined;

if (itemIsItemRequired(item)) {
    const itemRequired: ItemRequired = item; // this works
}
person OliverRadini    schedule 31.05.2020

ในขณะนี้ Typescript ไม่ได้อนุมานประเภทจาก การไหลแบบมีเงื่อนไขของคำสั่ง

const item: Item = {} as any;
if (item.left) {
    const itemRequired: ItemRequired = item; 
}

ด้วยเหตุนี้ บล็อกโค้ดด้านบนจึงไม่ทำให้ประเภทรายการแคบลงจาก Item ถึง ItemRequired ดังนั้น คุณกำลังพยายามกำหนดประเภทที่เข้ากันไม่ได้สองประเภทให้กับคอมไพลเลอร์ - ประเภทหนึ่งที่ด้านซ้ายเป็นข้อบังคับ และประเภทอื่นที่เป็นทางเลือก

อีกทางเลือกหนึ่ง ดังที่คุณกล่าวไว้ คุณสามารถเขียน type guard หรือเพียงทำสิ่งต่อไปนี้

const itemRequired: ItemRequired = item as ItemRequired;

อย่างไรก็ตาม แนะนำให้ใช้ตัวป้องกันประเภทการเขียนเสมอ

person Nafiz Ahmed    schedule 31.05.2020