Виключіть властивість із типу


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підмножина перетину з 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

За допомогою typecript 2.8 ви можете використовувати новий вбудований Excludeтип. У нотатках 2,8 релізу на насправді говорити про це в розділі «зумовленої умовні типів»:

Примітка. Тип Exclude - це належна реалізація запропонованого тут типу Diff. [...] Ми не включили тип Оміт, тому що він тривіально пишеться як 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 };,?
Квертій

1
Цей варіант ідеально підходить для старої версії машинопису. Я не міг отримати прихильну відповідь працювати на 2.3, але цей відмінно працював.
k0pernikus

6

Якщо ви віддаєте перевагу використовувати бібліотеку, використовуйте ts-basics .

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, помічник пропуску буде включений: TypeScript 3.5 RC - тип опускання помічника

Ви можете використовувати його безпосередньо, і ви повинні видалити власне визначення помічника пропускати під час оновлення.



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.