433

I'd like to exclude a single property from the type. How can I do that?

For example I have

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

And I want to exclude property z to get

type XY = { x: number, y: number };
BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
Qwertiy
  • 19,681
  • 15
  • 61
  • 128

8 Answers8

750

For versions of TypeScript at or above 3.5

In TypeScript 3.5, the Omit type was added to the standard library. See examples below for how to use it.

For versions of TypeScript below 3.5

In TypeScript 2.8, the Exclude type was added to the standard library, which allows an omission type to be written simply as:

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

For versions of TypeScript below 2.8

You cannot use the Exclude type in versions below 2.8, but you can create a replacement for it in order to use the same sort of definition as above. However, this replacement will only work for string types, so it is not as powerful as 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>>

And an example of that type in use:

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}
vsync
  • 118,978
  • 58
  • 307
  • 400
CRice
  • 29,968
  • 4
  • 57
  • 70
  • Great! You are declaring `Diff` (with `T` and `U` as types available for keys) as a `T`-keyed subset of an intersection of 3 types: type with key same as a value for `T`, type with `never` for `U` and type with `never` for all keys. Then you pass it through indexer to get correct values types. Am I right? – Qwertiy Jan 11 '18 at 21:43
  • 8
    Yep! But this does have a drawback. For example, `Omit<{a?: string, b?: boolean}, "b">` results in `{a: string | undefined}`, which still accepts `undefined` as a value, but loses the optional modifier on `a`. :( – CRice Jan 11 '18 at 21:57
  • That's sad.. Interesting that way with declare and spread keeps optional modifier... Is there some other way to keep it? – Qwertiy Jan 11 '18 at 22:09
  • Replace your `Omit` by `type Omit = Pick>;` and it'll be perfect :) – Qwertiy Jan 11 '18 at 23:20
  • 1
    @Qwertiy It works! Many thanks! I edited the post. But I wonder what the difference was, since what was there was literally identical to the type definition for `Pick` as far as I can see. – CRice Jan 11 '18 at 23:54
  • I don't see a definition of `Pick` in [news](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html), but in the [code](https://github.com/Microsoft/TypeScript/blob/f6603cd9f2bc4a30705a682e446b2cb04dfe3fc4/src/lib/es5.d.ts#L1320) it's really the same... – Qwertiy Jan 12 '18 at 07:05
  • Excellent! I believe this should be used in any introduction to advanced Typescript! – Nikos Paraskevopoulos May 11 '18 at 07:54
  • Note that only properties are considered. The new type will not contain any calling signatures of the original type. – James Wilkins Apr 08 '19 at 20:24
  • 5
    Note that for TS 3.5, the standard library's definition of `Omit` differs from that given here. In the stdlib, it is `type Omit = Pick>;` The change, while slight, [has caused some debate](https://github.com/microsoft/TypeScript/issues/30825), so be aware of the difference. – CRice May 20 '19 at 02:04
  • 1
    Note that this doesn't complain if the property you are trying exclude doesn't exist. For example, `Omit` is still valid. If you don't want that, you can use `StrictOmit` from [ts-essentials](https://github.com/krzkaczor/ts-essentials#StrictOmit) instead. This is useful if you want to make sure renaming the property accidentally doesn't break the omit rule. – CookieEater Nov 08 '19 at 21:05
  • @CRice Could you please have a look at my issue as you seems quite good with this. – Alen.Toma Mar 07 '23 at 20:17
159

Omit ...

single property

type T1 = Omit<XYZ, "z"> // { x: number; y: number; }

multiple properties

type T2 = Omit<XYZ, "y" | "z"> // { x: number; } 

properties conditionally

e.g. all string types:

type Keys_StringExcluded<T> = 
  { [K in keyof T]: T[K] extends string ? never : K }[keyof T]

type XYZ = { x: number; y: string; z: number; }
type T3a = Pick<XYZ, Keys_StringExcluded<XYZ>> // { x: number; z: number; }

Shorter version with TS 4.1 key remapping / as clause in mapped types (PR):

type T3b = { [K in keyof XYZ as XYZ[K] extends string ? never : K]: XYZ[K] } 
// { x: number; z: number; }

properties by string pattern

e.g. exclude getters (props with 'get' string prefixes)

type OmitGet<T> = {[K in keyof T as K extends `get${infer _}` ? never : K]: T[K]}

type XYZ2 = { getA: number; b: string; getC: boolean; }
type T4 = OmitGet<XYZ2> //  { b: string; }

Note: Above template literal types are supported with TS 4.1. You can also write get${string} instead of get${infer _} here.

More infos

Pick, Omit and other utility types

How to Pick and rename certain keys using Typescript? (rename instead of exclude)

Playground

ford04
  • 66,267
  • 20
  • 199
  • 171
55

With typescript 2.8, you can use the new built-in Exclude type. The 2.8 release notes actually mention this in the section "Predefined conditional types":

Note: The Exclude type is a proper implementation of the Diff type suggested here. [...] We did not include the Omit type because it is trivially written as Pick<T, Exclude<keyof T, K>>.

Applying this to your example, type XY could be defined as:

type XY = Pick<XYZ, Exclude<keyof XYZ, "z">>
Jason Hoetger
  • 7,543
  • 2
  • 16
  • 18
31

I've found solution with declaring some variables and using spread operator to infer type:

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

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

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

It works, but I would be glad to see a better solution.

Qwertiy
  • 19,681
  • 15
  • 61
  • 128
15

In Typescript 3.5+:

interface TypographyProps {
    variant: string
    fontSize: number
}

type TypographyPropsMinusVariant = Omit<TypographyProps, "variant">
CorayThan
  • 17,174
  • 28
  • 113
  • 161
9

If you prefer to use a library, use 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: You will find lots of other useful stuff there ;)

Krzysztof Kaczor
  • 5,408
  • 7
  • 39
  • 47
5

Typescript 3.5

As of Typescript 3.5, the Omit helper will be included: TypeScript 3.5 RC - The Omit Helper Type

You can use it directly, and you should remove your own definition of the Omit helper when updating.

GonchuB
  • 705
  • 5
  • 8
3

I do like that:

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