Utility Types en TypeScript
Aprende sobre los Utility Types en TypeScript y cómo usarlos para mejorar tu código.
Los Utility Types en TypeScript son tipos genéricos que ya vienen incluidos en el lenguaje y nos ayudan a transformar tipos existentes sin tener que reescribirlos.
Si trabajas con DTOs, formularios, respuestas de API o validaciones, estos tipos te ahorran muchísimo tiempo.
Partial<T>
Hace que todas las propiedades de un tipo sean opcionales.
interface User {
id: number;
name: string;
email: string;
isAdmin: boolean;
}
function updateUser(id: number, fieldsToUpdate: Partial<User>) {
console.log(`Actualizando usuario ${id} con:`, fieldsToUpdate);
}
updateUser(1, { email: "nuevo@correo.com" });
updateUser(2, { name: "Ana", isAdmin: false });
Required<T>
Hace que todas las propiedades de un tipo (incluso las opcionales) sean requeridas.
interface AppConfig {
port?: number;
databaseUrl?: string;
environment: "development" | "production";
}
function finalizeConfig(config: AppConfig): Required<AppConfig> {
return {
port: config.port ?? 3000,
databaseUrl: config.databaseUrl ?? "mongodb://localhost/db",
environment: config.environment,
};
}
const finalConfig = finalizeConfig({ environment: "production" });
console.log("Configuración final:", finalConfig);
Omit<T, K>
Crea un tipo eliminando propiedades de otro tipo.
interface UserWithPassword {
id: number;
name: string;
email: string;
passwordHash: string;
}
type PublicUser = Omit<UserWithPassword, "passwordHash">;
const publicProfile: PublicUser = {
id: 1,
name: "Carlos",
email: "carlos@correo.com",
};
Pick<T, K>
Crea un tipo seleccionando solo ciertas propiedades.
interface BlogPost {
id: string;
title: string;
content: string;
author: string;
views: number;
tags: string[];
}
type PostPreview = Pick<BlogPost, "title" | "author" | "tags">;
const previewData: PostPreview = {
title: "Aprende Utility Types",
author: "Wickz",
tags: ["typescript", "desarrollo-web"],
};
Readonly<T>
Hace que las propiedades sean de solo lectura.
interface AppSettings {
apiUrl: string;
theme: "light" | "dark";
}
const settings: Readonly<AppSettings> = {
apiUrl: "/api/v1",
theme: "dark",
};
// settings.theme = "light"; // Error
Exclude<T, U>
Elimina de una unión los tipos asignables a U.
type RequestStatus = "loading" | "success" | "error";
type FinalStatus = Exclude<RequestStatus, "loading">;
const status: FinalStatus = "success";
Extract<T, U>
Hace lo contrario de Exclude: mantiene los tipos que sí coinciden.
type AppEvent = "click" | "hover" | "submit" | "keydown";
type MouseEvent = Extract<AppEvent, "click" | "hover">;
const mouseAction: MouseEvent = "click";
ReturnType<T>
Obtiene el tipo de retorno de una función.
function createAuthResponse(success: boolean) {
if (success) return { status: 200 as const, token: "abc-123" };
return { status: 401 as const, error: "Unauthorized" };
}
type AuthResponse = ReturnType<typeof createAuthResponse>;
const response: AuthResponse = { status: 200, token: "xyz-456" };
Parameters<T>
Obtiene los tipos de los parámetros de una función en forma de tupla.
function sendMessage(chatId: string, message: string, urgent?: boolean) {
return { ok: true, chatId, message, urgent };
}
type MessageParams = Parameters<typeof sendMessage>;
const messageArgs: MessageParams = ["#general", "Hola equipo", true];
sendMessage(...messageArgs);
NonNullable<T>
Elimina null y undefined de un tipo.
type MaybeString = string | null | undefined;
function processText(text: NonNullable<MaybeString>) {
console.log(text.trim());
}
const textInput: MaybeString = " Hola Mundo ";
if (textInput) {
processText(textInput);
}
Awaited<T>
Obtiene el tipo real resuelto por una promesa.
async function fetchUserData(id: number) {
return {
id,
name: "Elena",
email: "elena@correo.com",
isAdmin: true,
};
}
type FetchedUser = Awaited<ReturnType<typeof fetchUserData>>;
async function displayUser() {
const user: FetchedUser = await fetchUserData(10);
console.log(`Usuario obtenido con Awaited: ${user.name}`);
}
displayUser();
Y listo. Estos son los Utility Types que más se usan en el día a día.
Cuando empieces a combinarlos entre sí (por ejemplo Partial<Pick<T, "x" | "y">>), vas a notar que TypeScript se vuelve mucho más potente sin complicarte el código.