Menu

Omit en TypeScript: quitar propiedades de un tipo (ejemplos)

Omit<T, K> crea un tipo con todas las propiedades de T salvo las claves K. Aprende Omit con una y con varias claves, cómo sobrescribir el tipo de una propiedad, cómo quitar la propiedad en ejecución, Omit frente a Exclude y Pick, por qué Omit acepta claves que no existen, un Omit estricto y Omit sobre tipos unión.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Omit<T, K> es un utility type integrado que crea un tipo objeto con todas las propiedades de T salvo las claves que aparecen en K. El uso clásico: un tipo User que tiene password y una versión pública que no la tiene.

PublicUser se mantiene sincronizado con User: añade un campo a User y también aparece en PublicUser, mientras que password sigue fuera. Omit solo trabaja con tipos; la desestructuración de toPublic es lo que quita la propiedad del objeto real.

Omitir varias claves

El segundo argumento es una unión, así que puedes poner tantas claves como necesites con |:

«El tipo sin los campos que genera el servidor» es el Omit más común en código real: un solo tipo de modelo, y Omit deriva la forma de entrada para los formularios de creación y las peticiones a la API.

Cómo está definido Omit

Omit se construye con otros dos utility types:

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

Léelo desde dentro: keyof T es la unión de todas las claves, Exclude<keyof T, K> quita de esa unión las que no quieres y Pick conserva las claves que quedan. Así, Omit<User, "password"> es Pick<User, "id" | "name" | "email">. Como Pick recorre las claves de T, se conservan los modificadores readonly y ? de las propiedades que quedan.

Fíjate en la restricción: K extends keyof any, no K extends keyof T. Ese detalle es el tema de la siguiente sección.

Omit no comprueba que la clave exista

keyof any es string | number | symbol, así que Omit acepta cualquier clave, incluso una que T no tiene. Una errata compila y no quita nada:

Ningún error en ninguna parte, y la contraseña sale en el JSON. La restricción flexible se eligió a propósito cuando se añadió Omit en TypeScript 3.5. Los motivos del equipo: en código genérico las claves omitidas muchas veces no vienen de T (una función que fusiona dos objetos puede tipar su argumento rest como Omit<T1, keyof T2>), Exclude tampoco restringe su segundo parámetro, y una versión restringida habría roto muchos de los tipos Omit escritos a mano que ya tenían los proyectos. Para el código del día a día, una versión más estricta detecta la errata:

index.ts(10,36): error TS2344: Type '"pasword"' does not satisfy the constraint 'keyof User'.
index.ts(11,7): error TS2741: Property 'password' is missing in type '{ id: number; name: string; }' but required in type 'PublicUser'.

El primer error es el que importa: la clave se comprueba contra keyof User. El segundo es consecuencia del primero, porque no se omitió nada y PublicUser sigue exigiendo password. Corrige la ortografía a "password" y compila. Muchos proyectos lo definen una vez en un archivo de tipos compartido y lo usan en lugar de Omit.

Sobrescribir el tipo de una propiedad

Una interfaz no puede extender otra y cambiar una propiedad a un tipo incompatible: interface ApiUser extends User { id: string } falla con error TS2430: Interface 'ApiUser' incorrectly extends interface 'User'. Primero omite la propiedad y luego declárala de nuevo:

Con un type alias lo mismo es una intersección: type ApiUser = Omit<User, "id"> & { id: string }. Sin el Omit, la intersección User & { id: string } daría a id el tipo number & string, que es never.

Omit sobre tipos unión

Omit no es distributivo. Sobre una unión parte del keyof de la unión entera, que solo contiene las claves que comparten todos los miembros, así que las propiedades propias de cada miembro desaparecen:

index.ts(8,39): error TS2353: Object literal may only specify known properties, and 'radius' does not exist in type 'NewShape'.

NewShape pasó a ser { kind: "circle" | "square" }. Para omitir en cada miembro por separado, aplica Omit dentro de un conditional type distributivo:

T extends unknown ? ... : never siempre es verdadero; solo está ahí para que el conditional type se distribuya sobre la unión. La página de conditional types explica por qué funciona. Usa DistributiveOmit siempre que el tipo del que omites sea una unión discriminada.

Omitir una propiedad anidada

Omit solo mira las claves del primer nivel, así que Omit<Settings, "editor.wordWrap"> no quita nada (y, como se vio arriba, no se queja). Para quitar una propiedad un nivel más abajo, omite la propiedad padre y vuelve a añadirla con su propio Omit:

Settings["editor"] es un indexed access type: nombra el tipo del objeto anidado para que Omit pueda trabajar con él.

Quitar propiedades en ejecución

Omit solo cambia el tipo. Para producir un objeto sin esas propiedades, sácalas con una desestructuración o escribe un pequeño helper genérico cuyo tipo de retorno sea Omit:

El helper restringe K a keyof T, así que una clave mal escrita es un error en la llamada. La copia es superficial: los objetos anidados se comparten con el original.

Omit frente a Pick y Exclude

Trabaja conConservaEjemploResultado
Omit<T, K>tipos objetotodas las propiedades salvo KOmit<User, "password">{ id; name; email }
Pick<T, K>tipos objetosolo las propiedades de KPick<User, "id" | "name">{ id; name }
Exclude<U, M>tipos uniónlos miembros de la unión que no se pueden asignar a MExclude<"a" | "b" | "c", "a">"b" | "c"

Elige entre Omit y Pick según lo que deba pasar cuando crezca el tipo de origen. Omit incluye las propiedades nuevas automáticamente, lo que encaja con «todo menos el secreto». Pick nunca las incluye, lo que encaja con «exactamente estos campos» y es más seguro para todo lo que sale de tu servidor. Pick comprueba sus claves contra keyof T; Omit no.

Preguntas frecuentes

¿Qué hace Omit en TypeScript?

Omit<T, K> construye un tipo objeto nuevo con todas las propiedades de T salvo aquellas cuyas claves están en K. Omit<User, "password"> es User sin password. Solo cambia el tipo; no quita nada de un objeto en tiempo de ejecución.

¿Cómo omito varias propiedades en TypeScript?

Pasa una unión de claves como segundo argumento: Omit<User, "password" | "createdAt" | "updatedAt">. Se quitan todas las claves de la unión.

¿Qué diferencia hay entre Omit y Exclude?

Omit quita propiedades de un tipo objeto: Omit<{ a: 1; b: 2 }, "a"> es { b: 2 }. Exclude quita miembros de un tipo unión: Exclude<"a" | "b", "a"> es "b". Omit está implementado con Exclude: Pick<T, Exclude<keyof T, K>>.

¿Por qué Omit no da error con una clave que no existe?

Su parámetro de claves está restringido a keyof any (cualquier string, number o symbol), no a keyof T, así que una errata como Omit<User, "pasword"> compila y no quita nada. Define type StrictOmit<T, K extends keyof T> = Omit<T, K> para obtener un error con claves desconocidas.

¿Cómo quito una propiedad de un objeto en tiempo de ejecución en TypeScript?

Usa una desestructuración con un elemento rest: const { password, ...rest } = user;. TypeScript tipa rest como el objeto sin password, la misma forma que Omit<User, "password">, y la propiedad desaparece de verdad del objeto nuevo.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR