Tipos anidados y Literal Types en TypeScript

En esta clase nos metemos con dos ideas que te suben el nivel de tipado rápido:

  • Tipos anidados para modelar objetos reales (usuario con company, etc.) sin que tu tipo se vuelva un monstruo.
  • Literal Types para acotar valores posibles (roles, direcciones, niveles) y que TypeScript no te deje colar cualquier cosa.

Tipos anidados: cuando el mundo real tiene objetos dentro de objetos

Imagina un User que además tiene información de company. Puedes empezar definiéndolo inline, pero enseguida se ve mejor si extraes tipos.

1) Anidar un objeto (y hacerlo opcional)

type User = {
  name: string
  company?: {
    name: string
    employees: number
  }
}

Si no todos los usuarios tienen company, lo marcas como opcional con ?. Así TypeScript no se queja cuando falte, pero si existe, exige toda la forma del objeto.

2) Extraer el tipo anidado para reutilizarlo

Cuando el objeto anidado crece, lo correcto es sacarlo a un tipo propio:

type Company = {
  name: string
  employees: number
}

type User = {
  name: string
  company?: Company
}

Ventajas:

  • Reutilización: Company lo puedes usar en otros sitios.
  • Legibilidad: el tipo User se entiende de un vistazo.
  • Mantenibilidad: cambias Company en un sitio y se refleja en todo.

Literal Types: que el rol no sea “lo que a ti te dé la gana”

Si defines un rol como string, TypeScript te deja meter cualquier cosa y luego vienen los bugs.

type User = {
  name: string
  role: string // demasiado abierto
}

La solución: restringirlo a valores concretos usando unión de literales (aka Literal Types).

type Role = 'admin' | 'user' | 'editor'

type User = {
  name: string
  role: Role
}

Ahora:

  • Si pones role: 'asdasd', TypeScript te grita.
  • Y lo mejor: tienes autocompletado con los valores válidos.

No solo strings: también números y booleanos

Los Literal Types no son solo para texto. Puedes hacer cosas como:

type Answer = 'yes' | 'no' | true | false
type Level = 1 | 2 | 3 | 4
type Direction = 'left' | 'up' | 'down'

Esto se usa muchísimo en videojuegos, estados finitos, configuraciones, flags, etc.

Buenas prácticas rápidas

  • Si un objeto anidado empieza a repetirse o crecer → extrae un tipo.
  • Si un campo solo puede tener “unos pocos valores”Literal Types.
  • Prefiere nombres semánticos (Role, Direction, Company) en vez de repetir uniones por todo el código.

Ejercicios

  • Crea type Address y úsalo dentro de User como address?: Address.
  • Define type Status = 'idle' | 'loading' | 'success' | 'error' y tipa una función setStatus(status: Status).
  • Modela un GameConfig con difficulty: 1 | 2 | 3 y controls: 'keyboard' | 'gamepad'.

Resumen

  • Los tipos anidados te permiten describir objetos reales sin perder control.
  • Extraer tipos (como Company) hace tu código más limpio y reutilizable.
  • Los Literal Types evitan valores inválidos y te regalan autocompletado y seguridad extra.