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

typescript - วิธีรวมสอง partials ให้เป็นวัตถุสมบูรณ์?


ฉันมีอินเทอร์เฟซที่ต้องการพร็อพทั้งหมด อย่างไรก็ตาม การสร้างอ็อบเจ็กต์เป็นกระบวนการสองขั้นตอน ดังนั้นฉันวางแผนที่จะสร้างเวอร์ชัน Partial ของอ็อบเจ็กต์ 2 ตัว จากนั้นรวมเข้าด้วยกันเพื่อให้ตรงกับอินเทอร์เฟซที่ไม่ใช่แบบบางส่วน ตัวอย่าง:

interface IComplete {
    a: string,
    b: string
}

const part1: Partial<IComplete> = {
    a: 'hello'
}

const part2: Partial<IComplete> = {
    b: 'world'
}

const together: IComplete = {
    ...part1,
    ...part2
}

แม้ว่า together จะสมบูรณ์เสมอ แต่ตัวคอมไพเลอร์ก็แจ้งข้อผิดพลาด:

Type '{ a?: string; b?: string; }' is not assignable to type 'IComplete'.
   Property 'a' is optional in type '{ a?: string; b?: string; }' but required in type 'IComplete'.

สนามเด็กเล่น

มีวิธีแนะนำในการทำให้สำเร็จนี้หรือไม่? สิ่งนี้สำคัญสำหรับกรณีของฉันที่ว่าอินเทอร์เฟซ IComplete ไม่ ถูกทำให้เป็นส่วนบางส่วน กล่าวคือ props a และ b จะไม่เป็น null หรือ undefined

คำตอบ #1

คำตอบของ @RyanCavanaugh นั้นดี หนึ่งในวิธีที่จะให้การอนุมานประเภททำงานได้ในขณะที่ยังได้รับประโยชน์จากการที่คอมไพเลอร์ตรวจสอบว่า part1 และ part2 เป็น Partial<IComplete> คือใช้ฟังก์ชันช่วยด้านล่างนี้:

interface IComplete {
  a: string,
  b: string,
  c: (x: string) => number,
  d: (x: number) => string
}

// helper function
const asPartialIComplete = <T extends Partial<IComplete>>(t: T) => t;

const part1 = asPartialIComplete({
  a: 'hello',
  c: (x) => x.length
})

const part2 = asPartialIComplete({
  b: 'world',
  d: (x) => x + ""
});

const together: IComplete = {
  ...part1,
  ...part2
}

ในตัวอย่างข้างต้น ทั้ง part1 และ part2 ถูกจำกัดโดย asPartialIComplete ให้เป็นวัตถุ Partial<IComplete> ที่ถูกต้อง (ดังนั้นพารามิเตอร์ของเมธอด c และ d จะถูกอนุมานเป็น string และ number ตามลำดับ) แต่ประเภทของ part1 และ part2 แคบพอที่คอมไพเลอร์จะสามารถตระหนักได้ว่า typeof part1 & typeof part2 คือ IComplete.

หวังว่าสิ่งนั้นน่าจะช่วยได้ โชคดีนะ!

คำตอบ #2

วิธีที่ง่ายที่สุดคือการลบการกำหนดชนิดข้อมูลออกและปล่อยให้การสืบชนิดข้อมูลทำงานของมัน

interface IComplete {
    a: string,
    b: string
}

const part1 = {
    a: 'hello'
}

const part2 = {
    b: 'world'
}

const together: IComplete = {
    ...part1,
    ...part2
}

สิ่งนี้มีผลเสียบางประการ เช่น พารามิเตอร์ในนิพจน์ฟังก์ชันใน part1 หรือ part2 จะไม่ได้รับการอนุมานประเภท

แทนที่จะเป็นเช่นนั้นคุณสามารถใช้ Pick - น่าเสียดายที่คุณต้องเขียนคีย์ที่คุณเลือกจากแต่ละประเภทเมื่อใช้วิธีนี้:

interface IComplete {
    a: string,
    b: string,
    c: number
}

const part1: Pick<IComplete, "a"> = {
    a: 'hello'
}

const part2: Pick<IComplete, "b" | "c"> = {
    b: 'world',
    c: 43
}

const together: IComplete = {
    ...part1,
    ...part2
}

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