Исключить свойство из типа


160

Я хотел бы исключить одно свойство из типа. Как я могу это сделать?

Например у меня

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

И я хочу исключить собственность, zчтобы получить

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

Ответы:


337

Для версий 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подмножество с ключами на пересечении 3 типов: тип с ключом, таким же как значение для T, тип с neverдля Uи тип с neverдля всех ключей. Затем вы передаете его через индексатор, чтобы получить правильные типы значений. Я прав?
— Qwertiy

5
Ага! Но у этого есть недостаток. Например, Omit<{a?: string, b?: boolean}, "b">приводит к тому {a: string | undefined}, что все еще принимает undefinedв качестве значения, но теряет необязательный модификатор on a. :(
— CRice

Это печально .. Интересно, что с помощью метода Declare и Spread сохраняется необязательный модификатор ... Есть ли другой способ сохранить его?
— Qwertiy

1
@Qwertiy Это работает! Большое спасибо! Я редактировал пост. Но мне интересно, в чем разница, поскольку то, что там было, было буквально идентично определению типа, Pickнасколько я могу видеть.
— Крис

3
Обратите внимание, что для TS 3.5 определение стандартной библиотеки Omitотличается от приведенного здесь. В stdlib это type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;изменение, хотя и незначительное, вызвало некоторые споры , так что имейте в виду разницу.
— Крис

41

С машинописным текстом 2.8 вы можете использовать новый встроенный Excludeтип. В заметках 2,8 релиза на самом деле говорить об этом в разделе «предопределенной условные типов»:

Примечание. Тип Exclude является правильной реализацией предложенного здесь типа Diff. [...] Мы не включили тип Omit, потому что он тривиально записан как 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является одной из наиболее недооцененных особенностей машинописного текста.
— Джейсон Хетгер,

1
Умно, мне это нравится :)! (до 2.8)
— maxime1992

Как я могу добавить z с типом строки в вашем результате
— user602291

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

1
Этот идеально подходит для старой версии машинописи. Я не мог получить квалифицированный ответ на работу для 2.3, но этот работал отлично.
— k0pernikus

7

Если вы предпочитаете использовать библиотеку, используйте ts-essentials .

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: там вы найдете много других полезных вещей;)


5

Машинопись 3,5

Начиная с Typescript 3.5, будет включен помощник Omit: TypeScript 3.5 RC - Тип помощника Omit

Вы можете использовать его напрямую, и вы должны удалить свое собственное определение помощника Omit при обновлении.



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);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.