[ actualmente en mantenimiento ]
← Back

Lanzar antes de estar listo

4 min read

El sistema de tipos de TypeScript es potente, pero muchos desarrolladores solo rascan la superficie. Aquí hay patrones que uso regularmente para escribir código más mantenible.

Uniones Discriminadas

En lugar de propiedades opcionales que crean estados inválidos:

// ❌ Evitar: Múltiples propiedades opcionales
interface Result {
  data?: User
  error?: Error
  loading?: boolean
}

Usa uniones discriminadas:

// ✅ Mejor: Imposible representar estados inválidos
type Result =
  | { status: 'loading' }
  | { status: 'success'; data: User }
  | { status: 'error'; error: Error }

Ahora TypeScript puede reducir los tipos basándose en el campo status, y no puedes tener accidentalmente data y error al mismo tiempo.

Guardas de Tipos (Type Guards)

Crea funciones reutilizables para reducir tipos:

function isUser(value: unknown): value is User {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    'email' in value
  )
}

// Ahora TypeScript conoce el tipo después de la guarda
if (isUser(data)) {
  console.log(data.email) // TypeScript sabe que data es User
}

Tipos de Marca (Branded Types)

Evita mezclar tipos primitivos similares:

type UserId = string & { readonly brand: unique symbol }
type PostId = string & { readonly brand: unique symbol }

function getUser(id: UserId): User { /* ... */ }
function getPost(id: PostId): Post { /* ... */ }

// TypeScript evita mezclarlos
const userId = 'user-123' as UserId
getPost(userId) // ❌ ¡Error de tipo!

Aserciones Const (Const Assertions)

Obtén tipos literales precisos en lugar de tipos ampliados:

// Sin aserción const
const config = {
  env: 'production' // Tipo: string
}

// Con aserción const
const config = {
  env: 'production'
} as const // Tipo: 'production'

Útil para objetos de configuración y tipos de acción en gestión de estado estilo Redux.

Tipos Utilitarios (Utility Types)

Los tipos utilitarios integrados de TypeScript resuelven patrones comunes:

// Hacer todas las propiedades opcionales
type PartialUser = Partial<User>

// Hacer todas las propiedades requeridas
type CompleteUser = Required<User>

// Seleccionar propiedades específicas
type UserPreview = Pick<User, 'id' | 'name'>

// Omitir propiedades específicas
type UserWithoutPassword = Omit<User, 'password'>

// Extraer el tipo de retorno de una función
type Response = ReturnType<typeof fetchUser>

Conclusión

Estos patrones ayudan a detectar errores en tiempo de compilación en lugar de en tiempo de ejecución. Empieza a incorporarlos gradualmente; tu yo del futuro te lo agradecerá.

Lanzar antes de estar listo · Irwing Duran