intellisense - วิธีขยายชนิดไม่ระบุชื่อใน Typescript
เมื่อเชื่อมต่อฟังก์ชันใน typescript กับชนิดไม่ระบุชื่อตัวอย่างเช่นแบบนี้:
let array = [{ seed: 2 }, { seed: 3 }];
array
.map(i => ({ seed: i.seed, square: i.seed * i.seed }))
.forEach(i => console.log(`square for ${i.seed} is ${i.square}`));
ฉันจำเป็นต้องกำหนดประเภทไม่ระบุชื่อใหม่สำหรับฟังก์ชัน map ถ้าฉันมีหลายขั้นตอนที่สร้างคุณสมบัติใหม่ทั้งหมด ฉันจะต้องเขียนโค้ดการนิยามมากมายเพื่อให้คุณสมบัติทั้งหมดถูกนำไปด้วย ฉันสามารถใช้ $.extend (หรือ Object.assign) แต่ด้วยวิธีนั้นฉันจะสูญเสีย intellisense และการพิมพ์แบบเข้มงวด
array
.map(i => $.extend(i, { square: i.seed * i.seed }))
.forEach(i => console.log(`square for ${i.seed} is ${i.square}`));
ฉันจะขยายอ็อบเจ็กต์นิรนามโดยไม่ต้องกำหนดคุณสมบัติทั้งหมดใหม่ในขณะที่ยังคงการพิมพ์ที่เข้มงวดได้อย่างไร?
คำตอบ #1
ฉันได้พบวิธีแก้ปัญหาในที่สุด สิ่งนี้สามารถทำได้โดยประเภทตัดกัน (Intersection Types) ซึ่งสามารถใช้กับประเภทและคลาสที่ไม่ระบุชื่อได้ ในตัวอย่างด้านล่าง ฟังก์ชัน extend จะคัดลอกคุณสมบัติจากแต่ละวัตถุและคืนวัตถุของประเภทตัดกัน สิ่งนี้จะช่วยลดปริมาณโค้ดการกำหนดประเภทลงอย่างมากโดยไม่สูญเสียการแนะนำโค้ดอัจฉริยะและการกำหนดประเภทที่เข้มงวด
function extend<T, U>(first: T, second: U): T & U {
let result = <T & U>{};
for (let id in first) {
(<any>result)[id] = (<any>first)[id];
}
for (let id in second) {
if (!result.hasOwnProperty(id)) {
(<any>result)[id] = (<any>second)[id];
}
}
return result;
}
let array = [{ seed: 2 }, { seed: 3 }];
array
.map(i => extend(i, { square: i.seed * i.seed }))
.map(i => extend(i, { cube: i.square * i.seed }))
.forEach(i => console.log(`square for ${i.seed} is ${i.square} and cube is ${i.cube}`));
เหมือนกันในสนามเด็กเล่น
สิ่งนี้ถูกนำไปใช้เช่น ตัวอย่างใน core-js และคำนิยามประเภทของมันจะส่งคืนประเภท Intersection:
assign<T, U>(target: T, source: U): T & U;
คำตอบ #2
เพื่อเพิ่มคำตอบที่เข้าใจง่ายขึ้นเกี่ยวกับวิธีที่ใครบางคนสามารถขยายประเภทด้วยประเภทนิรนามโดยใช้ประเภทผสม ฉันได้สร้างตัวอย่างนี้ที่อธิบายมัน:
interface Animal {
name: string
}
// With named types:
interface Bear extends Animal {
honey: boolean
}
function giveHoney(bear: Bear) {
bear.honey = true;
}
const myBear: Bear = { name: 'Bob', honey: false };
giveHoney(myBear);
// With anonymous types (no need to explicitly define the Bear type):
function giveHoney(bear: Animal & { honey: boolean }) {
bear.honey = true;
}
const myBear = { name: 'Bob', honey: false };
giveHoney(myBear);
