Concepto clave
Planificar una aplicación con tipado desde cero significa diseñar primero los tipos antes de escribir código, estableciendo contratos claros entre componentes. Imagina construir un puente: primero defines los planos estructurales (tipos), luego colocas los materiales (implementación). En TypeScript avanzado, esto implica modelar el dominio completo con interfaces, tipos genéricos y utilidades como Pick, Omit o Partial para garantizar consistencia en arquitecturas complejas.
Este enfoque previene errores en tiempo de compilación, mejora la mantenibilidad y facilita la colaboración en equipos grandes. Por ejemplo, en un frontend con múltiples vistas y estados, definir tipos para props, estados y eventos desde el inicio evita "type drift" (deriva de tipos) donde las interfaces se desincronizan con la implementación real.
Cómo funciona en la práctica
Comienza identificando las entidades principales de tu aplicación. Para un e-commerce, podrían ser Product, User, Order. Define interfaces base:
interface Product {
id: string;
name: string;
price: number;
category: string;
}
interface User {
id: string;
email: string;
role: 'admin' | 'customer';
}Luego, usa tipos genéricos para crear variantes. Por ejemplo, un tipo para productos en carrito:
type CartItem = T & {
quantity: number;
addedAt: Date;
};
// Uso:
const item: CartItem = {
id: "123",
name: "Laptop",
price: 999,
category: "Electronics",
quantity: 1,
addedAt: new Date()
};Finalmente, estructura los módulos: crea archivos como types/product.ts, types/user.ts y exporta tipos para usarlos en componentes React o servicios.
Caso de estudio
Supongamos una app de gestión de tareas con arrastrar y soltar. Primero, modelamos el estado:
type TaskStatus = 'todo' | 'inProgress' | 'done';
interface Task {
id: string;
title: string;
description?: string;
status: TaskStatus;
assigneeId?: string;
}
interface Column {
id: string;
title: string;
taskIds: string[];
}
interface BoardState {
tasks: Record;
columns: Record;
columnOrder: string[];
}Usamos tipos para eventos de drag-and-drop:
type DragStartEvent = {
type: 'task';
taskId: string;
sourceColumnId: string;
};
type DropEvent = DragStartEvent & {
targetColumnId: string;
};
function handleDrop(event: DropEvent, state: BoardState): BoardState {
// Lógica para actualizar estado tipado
return updatedState;
}Esto asegura que los componentes reciban datos consistentes, reduciendo bugs en interacciones complejas.
Errores comunes
- Tipos demasiado amplios: Usar
anyounknownsin necesidad, perdiendo ventajas de TypeScript. Solución: Define tipos específicos; usaunknownsolo para datos externos con validación. - Duplicación de interfaces: Crear
UseryUserDTOseparados sin herencia. Solución: Extiende interfaces base o usa tipos utilitarios:type UserDTO = Pick. - Ignorar tipos genéricos en librerías: No parametrizar componentes React con props tipados. Solución: Usa
React.ComponentTypepara mayor seguridad. - Tipos desactualizados: Modificar implementación sin actualizar tipos. Solución: Integra verificación en CI/CD con
tsc --noEmit. - No planificar estados asíncronos: Dejar tipos para loading/error sin definir. Solución: Usa tipos unidos:
type AsyncState = { loading: true } | { data: T } | { error: string }.
Checklist de dominio
- He definido todas las entidades principales del dominio con interfaces o tipos.
- He utilizado tipos genéricos para crear variantes reutilizables (ej.,
PaginatedResponse). - He estructurado tipos en archivos lógicos (ej., carpeta
types/) y evitado ciclos de dependencia. - He modelado estados complejos (ej., formularios, drag-and-drop) con tipos unidos o intersecciones.
- He integrado tipos para librerías externas (ej., React Router, Redux) usando declaraciones o genéricos.
- He escrito tests de tipos con herramientas como
tsdpara verificar contratos. - He documentado tipos clave con comentarios JSDoc para mejorar la colaboración.
Diseñar tipos para un sistema de comentarios en tiempo real
Implementa un sistema de tipos para una funcionalidad de comentarios en tiempo real en una aplicación frontend. Sigue estos pasos:
- Crea una interfaz
Commentcon propiedades:id(string),content(string),authorId(string),timestamp(Date), yreplies(array de Comment). - Define un tipo genérico
ApiResponseque incluya campos paradata(T),status(200, 400, 500), ymessage(string opcional). - Modela el estado de la UI con un tipo unido:
CommentsUIStateque pueda ser'loading' | 'loaded' | 'error'. - Crea una función tipada
addReply(commentId: string, reply: Comment): ApiResponseque simule añadir una respuesta. - Escribe un ejemplo de uso en un archivo TypeScript, mostrando cómo se pasarían estos tipos a un componente React.
- Usa
Partialpara permitir comentarios incompletos durante la creación. - Considera usar
Recordpara almacenar comentarios por ID en el estado. - Para el tipo unido, define cada variante como un objeto con una propiedad discriminante (ej.,
{ state: 'loading' }).
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.