TypeScript | The Guide You Need to Learn the Omit Type

It is normal to use the common types such as string, number, dates, or generate custom types and interfaces to provide type definition to TypeScript code. However, TypeScript has other utility types such as the omit type to help you take your code to the next level. If you have never heard about this utility type before, don’t worry, we will do our best to explain what the omit type does in this article.

The omit utility type was introduced in TypeScript release 3.5 and it helps developers to generate new type definitions by omitting or excluding properties of an existing group to construct a new group, which is a subgroup of properties of an existing group.

The following image is a representation of what the omit type does. The SoccerPlayer is the main group and where the omit type is used. Also, we have the FreeAgent which is the final output from using the omit type on the main group.

Omit helper type creates a subgroup

Understanding the Omit type Definition

If you have TypeScript installed in your machine, the Omit utility type definition can be found in the file typescript/lib/lib.es5.d.ts. Also, the TypeScript repository is publicly accessible and you can access the pull request to include the new Omit type.

/**
 * Construct a type with the properties of T except for those in type K.
 */
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

If you pay close attention, the omit type is based on using another two utility types: the Pick and Exclude types.

Given the following Auto interface, we are going to break down how the omit type works.

interface Auto {
   make:string;
   model: string;
   year: number;
   brand: string;
}

If we follow the definition of the Omit type, we know it is equal to:

Pick<T, Exclude<keyof T, K>>;

We have to start breaking down into little pieces to understand each part of the “equation”.

Pick<T, Exclude<keyof T, K>>; // what is this?
Exclude<keyof T, K>           // what is this?
keyof T                       // what is this?
K                             // what is this?

T is the Auto interface and K is a string literal or union of string literals of properties that are excluded from T. Therefore, we have the following:

keyof Auto = 'make' | 'model' | 'year' | 'brand'
K = 'year'

Hence, Exclude<keyof T, K> is:

Exclude<'make' | 'model' | 'year' | 'brand', 'year'>

The Exclude type will “cancel” or exclude the property keys found in both, keyof T, K or from the left and the right side.

type NonExcludedAutoKeys = Exclude<'make' | 'model' | 'year' | 'brand', 'year'>;

// which is the same as
type NonExcludedAutoKeys = 'make' | 'model' | 'brand';

Knowing this, we have solved what

Exclude<keyof T, K>

which is in

Pick<T, Exclude<keyof T, K>>

Hence, we now have

Pick<T, 'make' | 'model' | 'brand'>

And since T is, again, the Auto interface, we just have to replace it in the “equation”:

Pick<Auto, 'make' | 'model' | 'brand'>

in which the Pick type generates a new object type based on the keys provided on the right side. Therefore, since Auto interface has the keys make, model, year, and brand, and the keys previously selected from the Exclude are make, model, and brand, the new object type will not include the year key.

type AutoWithoutYear = Pick<Auto, 'make' | 'model' | 'brand'>

// which is the same as
type AutoWithoutYear = {
   make:string;
   model: string;
   brand: string;
}

How to use the Omit type

Omitting a single key

Given the example in the image above, create the SoccerPlayer interface.

interface SoccerPlayer {
  firtName: string;
  lastName: string;
  team: string;
  dob: Date;
  careerGoals: number;
}

Then, generate a new type and provide a type definition using the syntax Omit<T, K> where T is an object type, and K is a string literal.

In the following example, we are going to generate a FreeAgent type by removing the team property key from the SoccerPlayer interface.

type FreeAgent = Omit<SoccerPlayer, 'team'>

const freeSoccerPlayer: FreeAgent = {
  firtName: 'Paul',
  lastName: 'Pogba',
  dob: new Date('15 March, 1993'),
  careerGoals: 28
}

Omitting multiple keys

To omit multiple keys from an object, pass a union of string literals in K.

In the next example, we generate a Person type off of SoccerPlayer by removing the team and careerGoals.

type Person = Omit<SoccerPlayer, 'team' | 'careerGoals'>

const soccerAgent: Person = {
  firtName: 'Carmine',
  lastName: 'Raiola',
  dob: new Date('4 November, 1967')
}

Note: Generating the Person type off of the SoccerPlayer is a little odd, as it is common to generate a Person interface first to extend its properties to generate a SoccerPlayer type or interface. I did this to show an example of omitting multiple property keys.

Recommendation: Have an existing defined object type to apply the omit type

The main aspect to know before using the omit type is to have defined an existing object type and decide the property values to remove from the property type.

Note: By saying the previous statement, we are not saying you have to have an existing object type to use it with the omit type helper (Omit<T, K>). In fact, you can provide T with a non-defined object type and the Omit type will still remove any property keys from the object.

type FreeAgent = Omit<{
  firtName: string;
  lastName: string;
  team: string;
  dob: Date;
  careerGoals: number;
}, 'team'>

However, using the omit type in this scenario clutters your code with extra stuff when you could have defined the type FreeAgent right away by manually excluding the team property.

type FreeAgent = {
  firtName: string;
  lastName: string;
  dob: Date;
  careerGoals: number;
}

How to use the Omit type when extending an interface?

If you have used the keyword extends on an interface to be inherited from another interface, you will find it a similar process using the omit type.

In the previous examples, we used the omit type to generate the type FreeAgent. However, we will generate a FreeAgent interface to demonstrate how to use the omit type to create a new interface.

interface FreeAgent extends Omit<SoccerPlayer, 'team'> { }

At first, it might seem pointless whether to generate an interface or a type using the omit utility type. However, generating a new interface will let you add new properties different from the properties inherited from another interface with the exception of the omitted properties.

interface FreeAgent extends Omit<SoccerPlayer, 'team'> { 
   status: string;
}

When to use the Omit utility type?

There is no right or wrong answer for when to use the omit type in TypeScript. It all comes down to what makes sense to use this utility type.

Create “View Models” without having different mutliple source of truth of an object

However, it is useful to use the omit type when working with interfaces that interact with different views that don’t necessarily require all properties of an object. For example, consider SoccerPlayer to resemble the same structure of a database, which could include other properties such as dateCreated, createdBy, dateUpdated, updatedBy, etc added to keep an audit trail of the data:

interface SoccerPlayer {
  id: string;
  firtName: string;
  lastName: string;
  team: string;
  dob: Date;
  careerGoals: number;
  dateCreated: Date;
  createdBy: string;
  dateUpdated: Date;
  updatedBy: string;
  isActive: boolean;
}

Now, think about generating a form to create a new SoccerPlayer in an application. Certainly, you won’t ask “audit trail” data to the user filling up the form. Hence, you could create a RegisterSoccerPlayer type and only include the properties for the data a user needs to fill out to generate a valid SoccerPlayer record.

type RegisterSoccerPlayer = Omit<SoccerPlayer, 'id' | 'dateCreated' | 'createdBy' | 'dateUpdated' | 'updatedBy' | 'isActive'>

Another example is to generate a “ViewModel” type of the data that will be extrictly available for the end user when displaying the list of SoccerPlayer records that are or not active.

type SoccerPlayerView = Omit<SoccerPlayer, 'id' | 'team' | 'dob'>

Override the property type of an existing object

What if the SoccerPlayer object data doesn’t match between the UI and the API? For instance, think of fields such as dateCreated or dateUpdated to be strings in the UI, but in the backend they are handle as timestamps or dates.

interface SoccerPlayerUI extends Omit<Soccer, 'dateCreated' | 'dateUpdated'> {
  dateCreated: string;
  dateUpdated: string;
} 

While it might look odd to have a property used as dateCreated to be a string type, cases like that are common when data is transformed or cast into a different format so it can be easily consumed on different services in a project.

Other TypeScript articles you might be interested in reading

There is a list of TypeScript articles you might be interested in checking out

If none of them are of your interest, feel free to check out the blog to check for more TypeScript and other web development-related articles.

Conclusion

In summary, the omit type is defined using the combination of two other utility types, Pick and Exclude, that used in a specific “equation” leads to a logical way of omitting or removing properties of an existing object type to generate a new object type.

Did you like this article?

Share your thoughts by replying on Twitter of Become A Better Programmer or to personal my Twitter account.