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.
Table of Contents
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
- TypeScript | Learn How to Pass a Function as a Parameter
- Understanding the Question Mark (?:) in TypeScript
- How to Use Optional and Default Parameters in TypeScript?
- TypeScript | The Unknown Type Guide
- TypeScript | Organizing and Storing Types and Interfaces
- TypeScript | Double Question Marks (??) – What it Means
- TypeScript | Objects with Unknown Keys and Known Values
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.