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
}
