ยกเว้นคุณสมบัติจากประเภท


159

ฉันต้องการยกเว้นคุณสมบัติเดียวจากประเภท ฉันจะทำสิ่งนั้นได้อย่างไร

เช่นฉันมี

interface XYZ {
  x: number;
  y: number;
  z: number;
}

และฉันต้องการยกเว้นคุณสมบัติzเพื่อรับ

type XY = { x: number, y: number };

คำตอบ:


336

สำหรับเวอร์ชันของ TypeScript ที่หรือสูงกว่า 3.5

ใน TypeScript 3.5 Omitประเภทจะถูกเพิ่มเข้าไปในไลบรารีมาตรฐาน ดูตัวอย่างด้านล่างสำหรับวิธีใช้

สำหรับเวอร์ชันของ TypeScript ที่ต่ำกว่า 3.5

ใน TypeScript 2.8, Excludeชนิดถูกเพิ่มเข้ากับไลบรารีมาตรฐาน, ซึ่งอนุญาตให้เขียนชนิดการละเว้นได้อย่างง่าย ๆ ดังนี้:

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

สำหรับเวอร์ชันของ TypeScript ด้านล่าง 2.8

คุณไม่สามารถใช้Excludeประเภทในรุ่นที่ต่ำกว่า 2.8 ได้ แต่คุณสามารถสร้างการแทนที่เพื่อใช้การกำหนดประเภทเดียวกันตามที่กล่าวไว้ข้างต้น Excludeอย่างไรก็ตามการเปลี่ยนนี้จะทำงานประเภทสตริงดังนั้นจึงไม่เป็นพลังเป็น

// Functionally the same as Exclude, but for strings only.
type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T]
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>

และตัวอย่างของประเภทที่ใช้งานอยู่:

interface Test {
    a: string;
    b: number;
    c: boolean;
}

// Omit a single property:
type OmitA = Omit<Test, "a">; // Equivalent to: {b: number, c: boolean}

// Or, to omit multiple properties:
type OmitAB = Omit<Test, "a"|"b">; // Equivalent to: {c: boolean}

ที่ดี! คุณกำลังประกาศDiff<T, U>(ที่มีTและUเป็นชนิดที่มีอยู่สำหรับคีย์) เป็นTเซต -keyed ตัดของ 3 ประเภทคือ: ประเภทที่มีคีย์เดียวกับค่าสำหรับTชนิดที่มีneverสำหรับUและประเภทที่มีneverกุญแจทั้งหมด จากนั้นคุณส่งผ่านตัวสร้างดัชนีเพื่อรับชนิดค่าที่ถูกต้อง ฉันถูกไหม?
Qwertiy

5
อ้อ! แต่นี่จะมีข้อเสียเปรียบ ตัวอย่างเช่นOmit<{a?: string, b?: boolean}, "b">ผลใน{a: string | undefined}ซึ่งยังคงรับundefinedเป็นค่า aแต่สูญเสียปรับปรุงตัวเลือกบน :(
CRice

มันน่าเศร้า .. วิธีที่น่าสนใจเมื่อมีการประกาศและแพร่กระจายก็ช่วยปรับปรุงตัวเลือกเพิ่มเติม ... มีวิธีอื่นอีกไหมที่จะรักษามันไว้?
Qwertiy

1
@Qwertiy มันได้ผล! ขอบคุณมาก! ฉันแก้ไขโพสต์ แต่ฉันสงสัยว่าความแตกต่างคืออะไรเนื่องจากมีสิ่งใดที่เหมือนกันอย่างแท้จริงกับคำจำกัดความประเภทPickเท่าที่ฉันเห็น
CRice

3
โปรดทราบว่าสำหรับ TS 3.5 คำจำกัดความของไลบรารีมาตรฐานOmitแตกต่างจากที่ระบุไว้ที่นี่ ใน stdlib มันคือtype Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;การเปลี่ยนแปลงในขณะที่เล็กน้อยทำให้เกิดการถกเถียงกันบ้างดังนั้นจงระวังความแตกต่าง
CRice

41

ด้วย typescript 2.8 คุณสามารถใช้Excludeชนิดบิวด์อินใหม่ได้ บันทึก 2.8 ปล่อยจริงกล่าวถึงนี้ในส่วน "ที่กำหนดไว้ล่วงหน้าประเภทเงื่อนไข":

หมายเหตุ: ประเภทการแยกเป็นการใช้งานประเภท Diff ที่แนะนำที่นี่ [... ] เราไม่ได้รวม Omit type เพราะมันเขียนเป็นเรื่องPick<T, Exclude<keyof T, K>>เล็กน้อย

การใช้สิ่งนี้กับตัวอย่างของคุณประเภท XY สามารถกำหนดเป็น:

type XY = Pick<XYZ, Exclude<keyof XYZ, "z">>

19

ฉันได้พบวิธีแก้ปัญหาด้วยการประกาศตัวแปรบางอย่างและใช้ผู้ประกอบการแพร่กระจายเพื่ออนุมานประเภท

interface XYZ {
  x: number;
  y: number;
  z: number;
}

declare var { z, ...xy }: XYZ;

type XY = typeof xy; // { x: number; y: number; }

มันใช้งานได้ แต่ฉันยินดีที่จะเห็นทางออกที่ดีกว่า


3
นี่เป็นวิธีการแก้ปัญหาก่อนหน้า 2.8 ที่ยอดเยี่ยม typeofเป็นหนึ่งในคุณสมบัติที่ด้อยค่ามากขึ้นของ typescript
Jason Hoetger

1
ฉลาดฉันชอบมัน :)! (สำหรับ 2.8 ก่อน)
maxime1992

ฉันจะเพิ่ม z พร้อมสตริงประเภทในผลลัพธ์ของคุณได้อย่างไร
602291

@ user602291, type Smth = XY & { z: string };?
Qwertiy

1
อันนี้เหมาะสำหรับ typescript รุ่นเก่า ฉันไม่สามารถรับคำตอบที่ได้ผลสำหรับ 2.3 แต่อันนี้ใช้งานได้ดี
k0pernikus

6

หากคุณต้องการใช้ห้องสมุดใช้TS-ข้อมูลสำคัญ

import { Omit } from "ts-essentials";

type ComplexObject = {
  simple: number;
  nested: {
    a: string;
    array: [{ bar: number }];
  };
};

type SimplifiedComplexObject = Omit<ComplexObject, "nested">;

// Result:
// {
//  simple: number
// }

// if you want to Omit multiple properties just use union type:
type SimplifiedComplexObject = Omit<ComplexObject, "nested" | "simple">;

// Result:
// { } (empty type)

PS: คุณจะพบสิ่งที่มีประโยชน์อื่น ๆ อีกมากมายที่นั่น;)




0

ฉันชอบที่:

interface XYZ {
  x: number;
  y: number;
  z: number;
}
const a:XYZ = {x:1, y:2, z:3};
const { x, y, ...last } = a;
const { z, ...firstTwo} = a;
console.log(firstTwo, last);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.