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

TypeScript: วิธีการใช้ type guard กับ union type


ฟังก์ชัน compose สามารถมีออบเจ็กต์หรืออาร์เรย์ของออบเจ็กต์เป็นอาร์กิวเมนต์ ใน compose ตัวตรวจสอบชนิด (type guard) จะแยกความแตกต่างระหว่างออบเจ็กต์กับอาร์เรย์ ฟังก์ชัน mapper สามารถจัดการเฉพาะออบเจ็กต์ได้เท่านั้น และโดยการใช้ตัวตรวจสอบชนิด จะมีการส่งเฉพาะออบเจ็กต์ไปให้มัน

interface Link {
   something: string;
}

function compose(link: Link|Link[]) {
  if (link instanceof Array) {
    R.map(function(l) {
      return mapper(l);
    }, link);
  } else {
      return mapper(link);
  }
}

function mapper(link: Link) {
  return link;
}

การคอมไพล์ตัวอย่างนี้ทำให้เกิดข้อผิดพลาด:

ข้อผิดพลาด TS2345: อาร์กิวเมนต์ประเภท 'Link | Link[]' ไม่สามารถกำหนดค่าให้กับพารามิเตอร์ประเภท 'Link' ได้

ข้อผิดพลาดนี้สามารถเข้าใจได้เนื่องจาก mapper ได้รับประเภท union เป็นอาร์กิวเมนต์ แต่คาดหวังเพียงวัตถุเดียว นี่ไม่ใช่สิ่งที่ฉันคาดหวังเมื่อใช้ type guard มีความคิดเห็นอะไรเกี่ยวกับเรื่องนี้ไหม?

คำตอบ #1

ดูเหมือนว่า TypeScript 1.4.0.0 จะไม่สรุปว่า link ต้องเป็นชนิด Link เมื่อมันไม่ใช่ชนิด Array การเปลี่ยนแปลงเล็กน้อยน่าจะช่วยแก้ปัญหานั้นได้:

function compose(link: Link|Link[]) {
  if (link instanceof Array) {
    R.map(function(l) {
      return mapper(l);
    }, link);
  } else if (link instanceof Link) {
      return mapper(link);
  }
}

หรือคุณอาจระบุประเภท:

return mapper(<Link> link);