Domina los tipos de utilidades de TypeScript para RR. HH.

TypeScript

Tiempo estimado de lectura: 4 min

  • Ideas clave:
  • Usa los Utility Types para derivar tipos desde una única fuente de verdad y evitar duplicación.
  • Partial/Required/Readonly transforman la optionalidad e inmutabilidad de propiedades.
  • Pick/Omit/Record y las utilidades de unión (Exclude/Extract/NonNullable) refinan shapes sin reescribir interfaces.
  • ReturnType y Parameters facilitan mantener firmas coherentes entre capas.

Tipos de utilidades de TypeScript: una guía completa con ejemplos. Si escribes TypeScript habitualmente, dominar los Utility Types es una inversión que reduce deuda técnica y elimina duplicación. Aquí tienes una guía práctica, con ejemplos reales y criterio para decidir cuándo usar cada utilidad. Referencia oficial

Resumen rápido (lectores con prisa)

Qué es: Conjunto de tipos utilitarios para transformar y derivar tipos existentes sin reescribirlos.
Cuándo usarlo: Para evitar duplicación, expresar intención y derivar DTOs.
Por qué importa: Mantiene un único modelo como fuente de verdad y facilita refactors.
Cómo funciona: Aplica transformaciones a tipos (p. ej. Partial, Pick, ReturnType) para crear nuevos tipos derivados.

Transformaciones de propiedades: Partial, Required, Readonly

Partial

Partial: convierte todas las propiedades en opcionales. Ideal para operaciones PATCH o formularios de edición.

interface Usuario { id: number; nombre: string; email: string; }
type UsuarioPatch = Partial; // { id?: number; nombre?: string; email?: string }

Required

Required: fuerza todas las propiedades como obligatorias. Útil tras fusionar defaults.

interface Opts { timeout?: number; retries?: number; }
type OptsFull = Required; // timeout y retries obligatorios

Readonly

Readonly: marca todas las propiedades como inmutables a nivel de tipo.

type Estado = Readonly<{ id: number; name: string }>;

Criterio: usa Partial para inputs opcionales; Required cuando internamente necesitas garantías; Readonly para estado inmutable o contratos públicos que no deben mutarse.

Selección y exclusión de campos: Pick, Omit

Pick<Type, Keys>

Pick<Type, Keys>: crea un subtipo eligiendo propiedades concretas.

interface Producto { id: string; nombre: string; precio: number; costo: number; }
type ProductoCard = Pick<Producto, "id" | "nombre" | "precio">;

Omit<Type, Keys>

Omit<Type, Keys>: construye un tipo excluyendo propiedades.

type ProductoPublico = Omit<Producto, "costo">;

Criterio: Pick cuando seleccionas unas pocas propiedades; Omit cuando quieres el tipo completo menos unas cuantas.

Mapas y diccionarios: Record

Record<Keys, Type>: tipa objetos clave-valor. Mejor que usar { [k: string]: any }.

type Rol = "admin" | "user" | "guest";
const permisos: Record<Rol, boolean> = { admin: true, user: true, guest: false };

Criterio: usa Record cuando las claves son un union literal conocido. Para claves dinámicas complejas, considera Map o estructuras con validación.

Filtrado de uniones: Exclude, Extract, NonNullable

Exclude<Type, ExcludedUnion>

Exclude<Type, ExcludedUnion>: elimina miembros de una unión.

type Estado = "idle" | "loading" | "success" | "error";
type EstadoFinal = Exclude<Estado, "idle" | "loading">; // "success" | "error"

Extract<Type, Union>

Extract<Type, Union>: extrae los miembros que intersectan con otro union.

type Evento = string | number | (() => void);
type Callbacks = Extract<Evento, Function>; // () => void

NonNullable

NonNullable: elimina null y undefined.

type Res = string | null | undefined;
type ResNoNull = NonNullable<Res>; // string

Criterio: utiliza estas utilidades para refinar tipos en APIs donde algunas variantes no aplican o después de comprobaciones runtime.

Inferencia de funciones: ReturnType, Parameters

ReturnType

ReturnType: infiere el tipo de retorno de una función.

function crearConfig() { return { host: "db", port: 5432 }; }
type Config = ReturnType<typeof crearConfig>; // { host: string; port: number }

Parameters

Parameters: infiere la tupla de parámetros de una función.

function emitir(event: string, payload: unknown, priority = 0) {}
type EmitArgs = Parameters<typeof emitir>; // [string, unknown, number?]

Criterio: emplea ReturnType/Parameters para evitar replicar firmas en middlewares, factories o adaptadores. Mantén typeof para que el tipo sea dependiente del símbolo real.

Ejemplos combinados y patrones prácticos

DTOs y seguridad

Define entidad completa y deriva DTO público con Omit.

interface UserEntity { id: string; name: string; passwordHash: string; email: string; }
type UserPublic = Omit<UserEntity, "passwordHash">;

Actualizaciones y defaults

Recibe Partial del cliente, aplica defaults y convierte a Required internamente.

function normalize(cfg: Partial<Conf>): Required<Conf> {
  return { timeout: cfg.timeout ?? 5000, retries: cfg.retries ?? 3 };
}

Mapeo de respuestas

Usa Record para indexar por IDs y ReturnType para inferir la forma del fetcher.

type FetchUsers = () => Promise<User[]>;
type Users = ReturnType<FetchUsers> extends Promise<infer U> ? U : never;
const byId: Record<string, Users[0]> = {};

Conclusión y criterio técnico

Los Utility Types son la palanca para escribir modelos que evolucionan sin romper todo. Reglas prácticas:

  • Define un model central y deriva DTOs y shapes con utilidades.
  • Prefiere Pick/Omit sobre redefinir interfaces.
  • Mantén RxJS/logic fuera del tipado; usa ReturnType y Parameters para conectar capas.
  • No abuses: Partial en exceso puede esconder requisitos; valida en runtime cuando importe.

Lee la referencia oficial para casos avanzados y condicionales de tipos: capítulo de conditional types

Dominar estas piezas te deja escribir APIs más robustas y refactorizables. El siguiente paso: aplicar estos patrones en un modelo real de tu app y observar cómo desaparecen los tipos duplicados y las inconsistencias.

FAQ

 

¿Qué es un Utility Type en TypeScript?

Un Utility Type es un tipo provisto por TypeScript que transforma tipos existentes sin reescribirlos, por ejemplo Partial, Pick, ReturnType. Se usan para derivar nuevos shapes a partir de una fuente de verdad.

¿Cuándo debo usar Partial?

Usa Partial para inputs opcionales como formularios de edición o endpoints PATCH donde no todos los campos son obligatorios. Evita abusar de Partial cuando la ausencia de campos puede ocultar requisitos críticos.

¿Cuál es la diferencia entre Pick y Omit?

Pick crea un subtipo seleccionando propiedades concretas; Omit crea un subtipo excluyendo propiedades. Usa Pick cuando quieres unas pocas propiedades y Omit para el tipo completo menos algunas.

¿Para qué sirve Record?

Record tipa objetos clave-valor con claves de un union literal conocido. Es útil para mapas indexados por roles o IDs cuando las claves son previsibles. Para claves dinámicas complejas considera Map o validación extra.

¿Cómo ayuda ReturnType en arquitecturas en capas?

ReturnType infiere automáticamente el tipo de retorno de una función, reduciendo duplicación de tipos entre capas (por ejemplo, fetchers y mappers). Se combina con condicionales (infer) para desestructurar tipos asíncronos.

¿Qué cuidados tener con Partial y validación?

Precaución: Partial puede ocultar requisitos importantes. Cuando la validez de los datos importa en runtime, aplica validación explícita y transforma Partial en un tipo requerido tras aplicar defaults o comprobaciones.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *