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

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);

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