DEV Community

David Garcia
David Garcia

Posted on

🧩 Understanding Why Omit and Pick Fail with Union Types

Omit and Pick are some of the most loved utility types in TypeScript. They let you create new types by excluding or selecting specific properties from an existing type.
However, when you use them with union types, their behavior can be misleading - and in some cases, break your type expectations

type Employee = {
 id: string
 name: string
 job_name: string
}
type Customer = {
 id: string
 name: string
 company: string
}
type Person = Employee | Customer
Enter fullscreen mode Exit fullscreen mode

❌ Problem: Using Omit Directly
Suppose you want to remove the id field from all personas:

type PersonWithoutId = Omit<Person, 'id'>
Enter fullscreen mode Exit fullscreen mode

🧨 Actual Result:

type PersonWithoutId = {
 name: string
}
Enter fullscreen mode Exit fullscreen mode

Only name survives. The fields job_name and company are lost.

Why?
Because Omit is not distributive over union types. It collapses the union into a common structure, then removes the property - resulting in a simplified, lossy type.

✅ Solution:

DistributiveOmit

We can fix this by explicitly distributing Omit across each union member:

type DistributiveOmit<T, K extends PropertyKey> = T extends any
 ? Omit<T, K>
 : never

type PersonWithoutId = DistributiveOmit<Person, 'id'>
Enter fullscreen mode Exit fullscreen mode

✅ Expected Result:

type PersonWithoutId =
 | { name: string; job_name: string }
 | { name: string; company: string }
Enter fullscreen mode Exit fullscreen mode

🧪 Same Fix for Pick

type DistributivePick<T, K extends keyof T> = T extends any
 ? Pick<T, K>
 : never

type BasicaPerson = DistributivePick<Person, 'id' | 'name'>
Enter fullscreen mode Exit fullscreen mode

🧠 Summary Table

Image description

Top comments (0)