5 Tipos de Utilidad de TypeScript que Deberías Conocer

El sistema de tipos de TypeScript se vuelve verdaderamente poderoso cuando descubres los tipos de utilidad—ayudantes integrados que transforman tipos existentes sin reescribirlos. Si alguna vez te has encontrado duplicando interfaces o luchando con modificaciones de tipos, estos cinco tipos de utilidad esenciales cambiarán la forma en que escribes código TypeScript.
Puntos Clave
- Los tipos de utilidad transforman tipos existentes sin reescribirlos, reduciendo la duplicación de código
- Partial hace que todas las propiedades sean opcionales, perfecto para operaciones de actualización
- Required hace obligatorias todas las propiedades, asegurando estructuras de datos completas
- Pick y Omit ayudan a crear interfaces enfocadas seleccionando o excluyendo propiedades
- Readonly previene mutaciones accidentales, esencial para patrones de datos inmutables
Qué Son los Tipos de Utilidad de TypeScript y Por Qué Importan
Los tipos de utilidad son tipos genéricos pre-construidos de TypeScript que construyen nuevos tipos transformando los existentes. En lugar de crear manualmente variaciones de tus interfaces, estas utilidades te permiten derivar nuevos tipos con modificaciones específicas—haciendo tu código más mantenible y reduciendo la duplicación de tipos.
Exploraremos cinco tipos de utilidad fundamentales que resuelven problemas comunes del mundo real: Partial, Required, Pick, Omit, y Readonly. Cada uno aborda escenarios específicos que encuentras diariamente en el desarrollo con TypeScript.
Partial<T>: Haciendo Todas las Propiedades Opcionales en TypeScript
El tipo de utilidad Partial transforma todas las propiedades de un tipo a opcionales, perfecto para operaciones de actualización donde solo modificas campos específicos.
Cuándo Usar Partial para Actualizaciones de Formularios
Considera una actualización de perfil de usuario donde los usuarios pueden cambiar campos individuales sin enviar el objeto completo:
interface User {
id: string;
name: string;
email: string;
avatar: string;
lastLogin: Date;
}
function updateUserProfile(userId: string, updates: Partial<User>) {
// Solo actualizar campos proporcionados
return api.patch(`/users/${userId}`, updates);
}
// Uso - solo actualizando email
updateUserProfile("123", { email: "new@email.com" });
Ejemplo de Tipo Partial con Código del Mundo Real
Las actualizaciones de estado en React se benefician significativamente de Partial:
const [user, setUser] = useState<User>(initialUser);
const updateUser = (updates: Partial<User>) => {
setUser(prev => ({ ...prev, ...updates }));
};
// Actualizar solo campos específicos
updateUser({ name: "Jane Doe", avatar: "new-avatar.jpg" });
Required<T>: Haciendo Obligatorias Todas las Propiedades en TypeScript
Required hace lo opuesto a Partial—hace obligatorias todas las propiedades opcionales, asegurando estructuras de datos completas.
Convirtiendo Propiedades Opcionales a Obligatorias
Esto resulta invaluable para la validación de configuraciones:
interface DatabaseConfig {
host?: string;
port?: number;
username?: string;
password?: string;
}
// Asegurar que todos los valores de configuración existan antes de conectar
type ValidatedConfig = Required<DatabaseConfig>;
function connectDatabase(config: ValidatedConfig) {
// Todas las propiedades garantizadas de existir
return createConnection(config);
}
Tipo Required en Acción
El envío de formularios a menudo requiere datos completos:
interface RegistrationForm {
username?: string;
email?: string;
password?: string;
terms?: boolean;
}
type CompleteRegistration = Required<RegistrationForm>;
function submitRegistration(data: CompleteRegistration) {
// Todos los campos deben estar llenos
api.post('/register', data);
}
Discover how at OpenReplay.com.
Pick<T, K>: Seleccionando Propiedades Específicas de Tipos
Pick crea un nuevo tipo seleccionando solo propiedades especificadas, ideal para crear interfaces enfocadas.
Creando Subconjuntos de Tipos Enfocados con Pick
Extrae solo lo que necesitas para componentes específicos:
interface Article {
id: string;
title: string;
content: string;
author: string;
publishedAt: Date;
tags: string[];
}
// El componente Card solo necesita estos campos
type ArticlePreview = Pick<Article, 'id' | 'title' | 'author'>;
function ArticleCard({ article }: { article: ArticlePreview }) {
return (
<div>
<h3>{article.title}</h3>
<p>por {article.author}</p>
</div>
);
}
Pick vs Omit: Eligiendo el Enfoque Correcto
Usa Pick cuando necesites pocas propiedades, Omit cuando excluyas pocas propiedades:
// Pick: Cuando necesitas 2-3 propiedades de un tipo grande
type UserSummary = Pick<User, 'id' | 'name'>;
// Omit: Cuando necesitas la mayoría de propiedades excepto unas pocas
type PublicUser = Omit<User, 'password'>;
Omit<T, K>: Excluyendo Propiedades de Tipos TypeScript
Omit crea un tipo excluyendo propiedades especificadas, perfecto para remover campos sensibles o internos.
Removiendo Datos Sensibles con Omit
Protege información sensible en respuestas de API:
interface UserAccount {
id: string;
email: string;
password: string;
creditCard: string;
publicProfile: boolean;
}
// Remover campos sensibles para API pública
type PublicUserData = Omit<UserAccount, 'password' | 'creditCard'>;
function getPublicProfile(userId: string): Promise<PublicUserData> {
return api.get(`/users/${userId}/public`);
}
Mejores Prácticas del Tipo de Utilidad Omit
Combina con otras utilidades para patrones poderosos:
// Remover campos internos y hacer opcionales los restantes
type UserUpdatePayload = Partial<Omit<User, 'id' | 'createdAt'>>;
Readonly<T>: Creando Tipos Inmutables en TypeScript
Readonly hace todas las propiedades inmutables, previniendo mutaciones accidentales y haciendo cumplir la integridad de datos.
Previniendo Mutaciones Accidentales con Readonly
Esencial para gestión de estado y configuración:
interface AppConfig {
apiEndpoint: string;
version: string;
features: string[];
}
type ImmutableConfig = Readonly<AppConfig>;
const config: ImmutableConfig = {
apiEndpoint: "https://api.example.com",
version: "1.0.0",
features: ["auth", "payments"]
};
// Error de TypeScript: Cannot assign to 'apiEndpoint' because it is a read-only property
config.apiEndpoint = "https://new-api.com"; // ❌
Propiedades Readonly y Props de React
Asegura que las props permanezcan sin cambios:
type UserCardProps = Readonly<{
user: User;
onSelect: (id: string) => void;
}>;
function UserCard({ user, onSelect }: UserCardProps) {
// Las props son inmutables dentro del componente
return <div onClick={() => onSelect(user.id)}>{user.name}</div>;
}
Combinando Múltiples Tipos de Utilidad para Patrones Avanzados
Los tipos de utilidad se vuelven aún más poderosos cuando se combinan:
interface DatabaseRecord {
id: string;
createdAt: Date;
updatedAt: Date;
deletedAt?: Date;
data: Record<string, unknown>;
}
// Crear un tipo para registros nuevos: sin timestamps, datos parciales
type NewRecord = Omit<DatabaseRecord, 'id' | 'createdAt' | 'updatedAt'> & {
data: Partial<DatabaseRecord['data']>;
};
// Tipo de actualización: todo opcional excepto ID
type UpdateRecord = Partial<Omit<DatabaseRecord, 'id'>> & Pick<DatabaseRecord, 'id'>;
Conclusión
Estos cinco tipos de utilidad—Partial, Required, Pick, Omit, y Readonly—forman la base del desarrollo efectivo con TypeScript. Eliminan definiciones de tipos repetitivas, hacen cumplir la seguridad de tipos, y hacen tu código más mantenible.
Comienza incorporando estos patrones en tu base de código. Empieza con Partial para operaciones de actualización, usa Omit para crear interfaces públicas seguras, y aprovecha Readonly para prevenir errores. A medida que te sientas cómodo, combínalos para crear transformaciones de tipos sofisticadas que se ajusten perfectamente a las necesidades de tu aplicación.
Preguntas Frecuentes
Sí, puedes anidar tipos de utilidad para crear transformaciones complejas. Por ejemplo, Partial y Omit funcionan bien juntos para crear cargas útiles de actualización que excluyen ciertos campos mientras hacen otros opcionales.
No, los tipos de utilidad son construcciones puramente de tiempo de compilación. TypeScript remueve toda la información de tipos durante la compilación, por lo que los tipos de utilidad tienen cero sobrecarga en tiempo de ejecución.
La extensión de interfaces crea nuevos tipos agregando propiedades, mientras que los tipos de utilidad transforman tipos existentes. Los tipos de utilidad ofrecen más flexibilidad para modificar tipos que no controlas o crear variaciones de tipos existentes.
Sí, TypeScript te permite crear tipos de utilidad personalizados usando tipos mapeados, tipos condicionales y tipos de plantilla literal. Comienza con utilidades integradas y crea personalizadas cuando identifiques patrones repetidos.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.