Loại trừ tài sản từ loại


156

Tôi muốn loại trừ một thuộc tính duy nhất khỏi loại. Làm thế nào tôi có thể làm điều đó?

Ví dụ tôi có

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

Và tôi muốn loại trừ tài sản zđể có được

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

Câu trả lời:


333

Đối với các phiên bản TypeScript ở mức hoặc trên 3,5

Trong TypeScript 3.5, Omitloại đã được thêm vào thư viện chuẩn. Xem các ví dụ dưới đây để biết cách sử dụng nó.

Đối với các phiên bản TypeScript dưới 3,5

Trong TypeScript 2.8, Excludeloại đã được thêm vào thư viện chuẩn, cho phép loại bỏ sót được viết đơn giản là:

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

Đối với các phiên bản TypeScript dưới 2.8

Bạn không thể sử dụng Excludeloại trong các phiên bản dưới 2.8, nhưng bạn có thể tạo một thay thế cho nó để sử dụng cùng một định nghĩa như trên. Tuy nhiên, sự thay thế này sẽ chỉ hoạt động đối với các loại chuỗi, vì vậy nó không mạnh bằng 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>>

Và một ví dụ về loại đang sử dụng:

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}

Tuyệt quá! Bạn đang tuyên bố Diff<T, U>(với TUnhư các loại có sẵn cho các phím) như là một Ttập hợp con -keyed của một giao điểm của 3 loại: loại có cùng quan trọng như giá trị cho T, gõ với nevercho Uvà loại có nevercho tất cả các phím. Sau đó, bạn chuyển nó qua bộ chỉ mục để có được các loại giá trị chính xác. Tôi có đúng không
Qwertiy

5
Vâng! Nhưng điều này có một nhược điểm. Ví dụ: Omit<{a?: string, b?: boolean}, "b">kết quả {a: string | undefined}, vẫn chấp nhận undefinedlàm giá trị, nhưng mất công cụ sửa đổi tùy chọn trên a. :(
CRice

Điều đó thật đáng buồn .. Thú vị theo cách đó với khai báo và lan truyền giữ cho công cụ sửa đổi tùy chọn ... Có cách nào khác để giữ nó không?
Qwertiy

1
@Qwertiy Nó hoạt động! Cảm ơn nhiều! Tôi đã chỉnh sửa bài viết. Nhưng tôi tự hỏi sự khác biệt là gì, vì những gì ở đó hoàn toàn giống với định nghĩa loại cho Pickđến mức tôi có thể thấy.
CRice

3
Lưu ý rằng đối với TS 3.5, định nghĩa của thư viện chuẩn Omitkhác với định nghĩa được đưa ra ở đây. Trong stdlib, đó là type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;Sự thay đổi, trong khi nhẹ, đã gây ra một số tranh luận , vì vậy hãy nhận thức được sự khác biệt.
CRice

41

Với bản in 2.8, bạn có thể sử dụng loại tích hợp mới Exclude. Các ghi chú 2.8 phát hành thực sự đề cập đến điều này trong phần "định trước loại có điều kiện":

Lưu ý: Loại Loại trừ là cách triển khai đúng loại Diff được đề xuất ở đây. [...] Chúng tôi không bao gồm loại Omit vì nó được viết một cách tầm thường là Pick<T, Exclude<keyof T, K>>.

Áp dụng điều này vào ví dụ của bạn, loại XY có thể được định nghĩa là:

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

19

Tôi đã tìm thấy giải pháp với việc khai báo một số biến và sử dụng toán tử trải rộng để suy ra kiểu:

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

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

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

Nó hoạt động, nhưng tôi sẽ rất vui khi thấy một giải pháp tốt hơn.


3
Đây là một giải pháp tiền 2.8 tuyệt vời. typeoflà một trong những tính năng được đánh giá thấp hơn của bản thảo.
Jason Hoetger

1
Thông minh, tôi thích nó :)! (cho trước 2.8)
maxime1992

Làm cách nào tôi có thể thêm z với chuỗi loại trong kết quả của bạn
user602291

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

1
Điều này là hoàn hảo cho phiên bản cũ của bản thảo. Tôi không thể có được câu trả lời được tích lũy để làm việc cho 2.3, nhưng câu trả lời này hoạt động rất tốt.
k0pernikus

6

Nếu bạn thích sử dụng thư viện, hãy sử dụng ts-Essential .

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: Bạn sẽ tìm thấy rất nhiều thứ hữu ích khác ở đó;)



4

Trong bản đánh máy 3.5+ :

interface TypographyProps {
    variant: string
    fontSize: number
}

type TypographyPropsMinusVariant = Omit<TypographyProps, "variant">

0

Tôi làm như thế:

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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.