Suggest an editImprove this articleRefine the answer for “Utility type omit in TypeScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Omit<T, K>** - a TypeScript utility type that creates a new type by removing keys `K` from type `T`. ```typescript interface User { id: string; name: string; email: string; password: string; } type PublicUser = Omit<User, "password">; // { id: string; name: string; email: string } ``` **Key point:** use `Omit` when you need most of a type but want to exclude a few fields, like stripping a password before sending an API response.Shown above the full answer for quick recall.Answer (EN)Image**Omit<T, K>** - a utility type that takes type `T` and returns the same type with every key listed in `K` removed. ## Theory ### TL;DR - Think of a form with certain fields blacked out: everything else stays intact, only the listed fields disappear - Main difference from `Pick`: `Omit` subtracts keys from a full type; `Pick` builds a new type by selecting only what you name - Decision rule: keys to exclude fewer than keys to keep? Use `Omit`. Need only a small subset? Use `Pick` - No runtime cost: `Omit` is erased during compilation to JavaScript - Works on top-level keys only; nested paths like `"address.zip"` have no effect ### Quick example ```typescript interface User { id: string; name: string; email: string; password: string; } type PublicUser = Omit<User, "password">; // Result: { id: string; name: string; email: string } // password is gone, nothing else changed ``` Two lines of type code, one removed field. That is the whole idea. ### Key difference `Pick<T, K>` builds a type from scratch by selecting only the named keys. `Omit<T, K>` starts from the full type and removes the listed keys, keeping everything else. If a type has 10 properties and you need 9 of them, `Omit` saves you from listing all 9 in `Pick`. ### When to use - API response without sensitive fields: `Omit<User, "password" | "internalId">` - React component props without internal callbacks: `Omit<ComponentProps, "onInternalClick">` - Database entity converted to DTO: `Omit<Entity, "createdBy" | "updatedAt">` - Form input type for record creation: `Omit<Product, "id" | "createdAt">` ### Omit vs Pick | Utility | What it does | Best for | |---|---|---| | `Pick<T, K>` | Keeps only named keys | Small subset from a large type (2-3 props) | | `Omit<T, K>` | Removes named keys, keeps the rest | Most props needed, exclude a few (secrets, internals) | | **Decision rule** | | Keys to exclude < keys to keep? Use `Omit`. Otherwise `Pick` | These two produce identical results: ```typescript interface User { id: string; name: string; email: string; password: string; createdAt: Date; } type A = Pick<User, "id" | "name" | "email">; type B = Omit<User, "password" | "createdAt">; // A and B are structurally identical ``` Use whichever makes the intent clearer at the call site. ### How the compiler handles Omit TypeScript expands `Omit<T, K>` using `Pick` and `Exclude` internally: ```typescript // TypeScript's built-in definition: type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>; // Step by step for Omit<User, "password">: // 1. keyof User = "id" | "name" | "email" | "password" | "createdAt" // 2. Exclude<keyof User, "password"> = "id" | "name" | "email" | "createdAt" // 3. Pick<User, "id" | "name" | "email" | "createdAt"> = the result ``` No runtime cost. The whole mechanism disappears after compilation to JavaScript. One more detail: `Omit` preserves index signatures. If your type has `[key: string]: unknown`, that stays in the result even after specific keys are removed. ### Common mistakes **1. Omitting a key that does not exist** ```typescript interface User { id: string; name: string; } type Wrong = Omit<User, "nonExistent">; // Compiles fine. No error. No effect. // TypeScript ignores keys in K that do not exist in T. ``` No crash, no warning. The type stays unchanged and you spend time wondering why nothing happened. **2. Expecting Omit to remove nested keys** ```typescript type UserWithAddress = { name: string; address: { street: string; zip: string }; }; // This has no effect: type Wrong = Omit<UserWithAddress, "address.zip">; // Result: { name: string; address: { street: string; zip: string } } ``` `Omit` is shallow. It only removes top-level keys. To drop a nested field, reconstruct the nested type manually or write a recursive utility type. **3. Using Omit on union types without distribution** ```typescript type Union = string | { id: string; secret: string }; type Attempt = Omit<Union, "secret">; // Result is not what you expect. // Omit does not distribute over union members automatically. ``` For unions, apply `Omit` to each member separately. **4. Re-adding an omitted key via extends** ```typescript type PublicUser = Omit<User, "password">; // This compiles: interface AdminUser extends PublicUser { password: string; // password is back } ``` Structural typing allows this. If the goal is to prevent `password` from appearing anywhere, this approach will not hold. Use an intersection type or a separate base instead. **5. Confusing Omit with Exclude** `Exclude<keyof T, K>` gives you a union of remaining key names as strings. `Omit<T, K>` gives you a new object type. Different outputs, different use cases. ### Real-world usage - **React**: `Omit<ComponentProps<'input'>, 'ref'>` in `forwardRef` wrappers (pattern used in React 18 typings) - **Zod**: `Omit<z.infer<typeof userSchema>, 'password'>` for public schema shapes - **Prisma**: `Omit<Prisma.UserGetPayload<{}>, 'passwordHash'>` in API response types - **tRPC**: procedure inputs via `Omit<FullInput, 'internalToken'>` - **Express**: narrowing request body types in middleware In my experience, `Omit` shows up most at API boundaries where you strip sensitive or server-only fields before the data reaches the client. That single pattern covers roughly 70% of real usages across codebases. ### Follow-up questions **Q:** What happens if `K` contains a key that does not exist in `T`? **A:** TypeScript compiles without error and ignores the unknown key. The resulting type is identical to `T`. **Q:** How does `Omit` handle index signatures like `[key: string]: unknown`? **A:** It preserves them. `Omit<{ [k: string]: any; foo: string }, 'foo'>` keeps the index signature and removes only `foo`. **Q:** What is the difference between `Omit<T, K>` and `Exclude<keyof T, K>`? **A:** `Exclude` returns a union of key names. `Omit` returns a full object type with those keys removed. One is a string union, the other is a usable object type. **Q:** How would you implement `Omit` from scratch? **A:** `type MyOmit<T, K extends keyof any> = { [P in keyof T as P extends K ? never : P]: T[P] }`. The `as` clause in the mapped type filters out matching keys by remapping them to `never`. **Q:** How does `Omit` behave with intersection types like `A & B`? **A:** It distributes: `Omit<A & B, K>` roughly equals `Omit<A, K> & Omit<B, K>`. The exact result depends on which type in the intersection actually holds the key. ## Examples ### Basic: removing a sensitive field ```typescript interface User { id: string; name: string; email: string; password: string; } type PublicUser = Omit<User, "password">; // { id: string; name: string; email: string } function getPublicUser(user: User): PublicUser { const { password, ...rest } = user; return rest; // TypeScript knows this matches PublicUser } ``` The spread destructuring pattern pairs naturally with `Omit`: the type describes the expected shape, the runtime code strips the actual value. ### Intermediate: DTO types for a CRUD API ```typescript interface Product { id: string; name: string; price: number; description: string; createdAt: Date; updatedAt: Date; } // POST /products - no id or timestamps (server sets those) type CreateProductDTO = Omit<Product, "id" | "createdAt" | "updatedAt">; // PATCH /products/:id - id comes from the URL, all fields optional type UpdateProductDTO = Partial<Omit<Product, "id">>; // These types prevent accidental sends of server-managed fields ``` `Omit` combined with `Partial` covers most CRUD shapes. Define the source type once and derive everything else from it. ### Advanced: React component props with forwardRef ```typescript import { forwardRef, InputHTMLAttributes } from "react"; interface CustomInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "ref"> { label: string; error?: string; } const CustomInput = forwardRef<HTMLInputElement, CustomInputProps>( ({ label, error, ...props }, ref) => ( <div> <label>{label}</label> <input ref={ref} {...props} /> {error && <span>{error}</span>} </div> ) ); ``` `Omit<InputHTMLAttributes<HTMLInputElement>, 'ref'>` strips the built-in `ref` prop so `forwardRef` can manage it directly. This is the exact pattern used in React 18 typings.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.