TypeScript Utility Types: Understanding Omit<T, K>

TypeScript Utility Types: Understanding Omit&lt;T, K&gt;

The Omit utility type removes properties from a type:

interface User {
    id: number;
    name: string;
    email: string;
    password: string;
}

type PublicUser = Omit<User, 'password'>;
// { id: number; name: string; email: string; }

PublicUser has all User properties except password.

Basic Syntax

Omit<Type, Keys>
  • Type: The original type
  • Keys: String literal or union of property names to exclude

Omitting Single Property

interface Product {
    id: string;
    name: string;
    price: number;
    internalNotes: string;
}

type PublicProduct = Omit<Product, 'internalNotes'>;
// { id: string; name: string; price: number; }

Omitting Multiple Properties

Use a union type:

type UserWithoutSensitiveData = Omit<User, 'password' | 'email'>;
// { id: number; name: string; }

Common Use Cases

API responses without internal fields:

interface InternalUser {
    id: number;
    name: string;
    email: string;
    password: string;
    createdAt: Date;
    internalNotes: string;
}

type APIUser = Omit<InternalUser, 'password' | 'internalNotes'>;

Form data without auto-generated fields:

interface Article {
    id: string;
    title: string;
    content: string;
    createdAt: Date;
    updatedAt: Date;
}

type ArticleFormData = Omit<Article, 'id' | 'createdAt' | 'updatedAt'>;
// { title: string; content: string; }

Update types without readonly fields:

interface Config {
    readonly version: string;
    apiUrl: string;
    timeout: number;
}

type MutableConfig = Omit<Config, 'version'>;
// Can modify apiUrl and timeout, but not version

Omit vs Pick

Pick selects properties. Omit excludes them:

type WithPick = Pick<User, 'id' | 'name'>;
// { id: number; name: string; }

type WithOmit = Omit<User, 'email' | 'password'>;
// { id: number; name: string; }

Same result, different approach. Use Pick when selecting few properties. Use Omit when excluding few properties.

Combining with Other Utility Types

Omit + Partial:

type OptionalExceptId = { id: string } & Partial<Omit<User, 'id'>>;
// { id: string; name?: string; email?: string; password?: string; }

Omit + Required:

interface PartialUser {
    id?: number;
    name?: string;
    email?: string;
}

type RequiredExceptId = Omit<PartialUser, 'id'> & Required<Pick<PartialUser, 'id'>>;
// { id: number; name?: string; email?: string; }

Function Parameter Types

Create parameter types by omitting irrelevant fields:

interface User {
    id: number;
    name: string;
    email: string;
    createdAt: Date;
}

function createUser(data: Omit<User, 'id' | 'createdAt'>) {
    return {
        id: generateId(),
        createdAt: new Date(),
        ...data
    };
}

createUser({ name: 'Alice', email: 'alice@example.com' });

Extending Omitted Types

Build on an omitted type:

interface BaseEntity {
    id: string;
    createdAt: Date;
    updatedAt: Date;
}

interface Article extends Omit<BaseEntity, 'id'> {
    id: number;  // Override id to be number instead of string
    title: string;
    content: string;
}

How Omit Works Internally

TypeScript implements Omit using Pick and Exclude:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
  1. keyof T gets all property names
  2. Exclude<keyof T, K> removes the specified keys
  3. Pick selects the remaining properties

Edge Cases

Omitting non-existent property:

type Test = Omit<User, 'nonExistent'>;
// Works - just returns User unchanged

TypeScript doesn't error on omitting properties that don't exist. This can hide typos.

Omitting all properties:

type Empty = Omit<User, 'id' | 'name' | 'email' | 'password'>;
// {} - empty object type

Generic Functions with Omit

function updateRecord<T extends { id: string }>(
    id: string,
    data: Omit<T, 'id'>
): T {
    return { id, ...data } as T;
}

const user = updateRecord<User>('123', {
    name: 'Alice',
    email: 'alice@example.com',
    password: 'secret'
});

Discriminated Unions

Omit with union types:

type Shape = 
    | { kind: 'circle'; radius: number }
    | { kind: 'rectangle'; width: number; height: number };

type ShapeWithoutKind = Omit<Shape, 'kind'>;
// { radius: number } | { width: number; height: number }

Real-World Example: API Client

interface BlogPost {
    id: string;
    title: string;
    content: string;
    authorId: string;
    createdAt: Date;
    updatedAt: Date;
}

class BlogAPI {
    async create(data: Omit<BlogPost, 'id' | 'createdAt' | 'updatedAt'>) {
        // Server generates these fields
        return fetch('/api/posts', {
            method: 'POST',
            body: JSON.stringify(data)
        });
    }
    
    async update(id: string, data: Partial<Omit<BlogPost, 'id' | 'createdAt'>>) {
        // Can update anything except id and createdAt
        return fetch(`/api/posts/${id}`, {
            method: 'PATCH',
            body: JSON.stringify(data)
        });
    }
}

When Not to Use Omit

If you're omitting most properties, define a new type:

// Awkward
type UserPreview = Omit<User, 'password' | 'email' | 'phone' | 'address' | 'bio'>;

// Better
interface UserPreview {
    id: number;
    name: string;
}

TypeScript Version

Omit was added in TypeScript 3.5. For earlier versions, use the manual implementation:

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

Further Reading

The TypeScript handbook's Omit documentation covers usage and examples.

Matt Pocock's TypeScript tips include advanced Omit patterns.

The TypeScript source shows how utility types are implemented.

Omit simplifies type manipulation in TypeScript.

Wear the code

Product mockup

Omit<T, K> Developer T-Shirt (TypeScript Edition — Dark Mode)

£25.00

View product
Product mockup

Omit<T, K> Developer T-Shirt (TypeScript Edition — Light Mode)

£25.00

View product

0 comments

Leave a comment

Please note, comments need to be approved before they are published.