Cómo excluir una propiedad de un tipo en TypeScript: salvando el código del lastre innecesario
\n\n¿Alguna vez te has encontrado en una situación en la que tienes una interfaz o tipo grande, y necesitas crear un nuevo tipo que es casi igual, pero sin uno o dos campos? ¿Duplicar todo el código? ¿Copiar 15 líneas y eliminar una? Hay una forma más elegante. Hoy veremos cómo excluir una propiedad de un tipo en TypeScript: esta es una de las utilidades más populares que evita la duplicación y hace que el código sea más limpio.
\n\nEste tema es un verdadero éxito en Stack Overflow. La pregunta "Exclude property from type" obtiene miles de visitas, porque tarde o temprano todo desarrollador se enfrenta a la necesidad de eliminar un campo de un tipo o excluir una propiedad de una interfaz. Vamos a desglosarlo en orden, comenzando con ejemplos simples y terminando con técnicas avanzadas.
\n\nEl problema: ¿por qué excluir campos de un tipo?
\n\nImagina que tienes una interfaz User:
interface User {\n id: number;\n name: string;\n email: string;\n password: string;\n createdAt: Date;\n}\n\nQuieres crear un formulario de registro donde el usuario ingrese nombre, email y contraseña. Pero id se genera en el servidor y createdAt es automático. Necesitas un tipo NewUser que contenga solo name, email y password. ¿Cómo hacerlo?
Una mala solución es declarar una nueva interfaz desde cero:
\n\ninterface NewUser {\n name: string;\n email: string;\n password: string;\n}\n\nEsto funciona, pero viola el principio DRY (Don't Repeat Yourself). Si cambiamos el tipo de name en User, también tendremos que cambiarlo en NewUser. Aquí es donde la exclusión de propiedades de un tipo viene al rescate.
El tipo utilitario Omit: la herramienta principal
\n\nTypeScript proporciona el tipo utilitario incorporado Omit<Type, Keys>. Crea un nuevo tipo excluyendo las claves especificadas del original. La sintaxis es simple:
type NewUser = Omit<User, 'id' | 'createdAt'>;\n\nAhora NewUser contiene solo name, email y password. Si cambiamos email a Email en User, NewUser lo recogerá automáticamente.
Verifiquemos en la práctica:
\n\nconst newUser: NewUser = {\n name: 'Ana',\n email: 'ana@example.com',\n password: 'segura123'\n}; // ✅ Todo bien\n\nconst invalidUser: NewUser = {\n name: 'Ana',\n email: 'ana@example.com',\n password: 'segura123',\n id: 1 // ❌ Error: id no existe en el tipo NewUser\n};\n\nNota: Omit funciona tanto con interfaces como con tipos. Es una herramienta universal para excluir campos de un tipo.
¿Cómo funciona Omit internamente?
\n\nPara entender mejor cómo TypeScript excluye propiedades de un tipo, echemos un vistazo bajo el capó. Omit es una combinación de otras dos utilidades: Pick y Exclude.
Así está definido en la biblioteca estándar de TypeScript:
\n\ntype Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;\n\nDesglosémoslo paso a paso:
\n- \n
keyof T— obtiene todas las claves del tipo T (por ejemplo,'id' | 'name' | 'email' | 'password' | 'createdAt') \n Exclude<keyof T, K>— excluye de esas claves las especificadas en K (obtenemos'name' | 'email' | 'password') \n Pick<T, ...>— selecciona de T solo las claves restantes \n
Por lo tanto, excluir una propiedad de una interfaz se reduce a filtrar claves. Elegante, ¿verdad?
\n\nPick: la cara opuesta de Omit
\n\nA veces es más fácil no excluir, sino al con