Objetos en TypeScript

En esta clase nos centramos en cómo trabajar correctamente con objetos en TypeScript. Después de ver arrays, ahora toca entender cómo tipar objetos de forma profesional, reutilizable y segura.

Vamos a ver qué hace TypeScript automáticamente, cuál es la forma no recomendada de tipar objetos y cómo hacerlo bien usando type alias, propiedades opcionales y readonly.

Inferencia automática de tipos

Cuando creamos un objeto como constante:

const user = {
  name: 'midudev',
  age: 30
}

TypeScript ya infiere automáticamente:

  • namestring
  • agenumber

Esto es gracias al sistema de inferencia. Muchas veces no necesitas escribir nada más.

Pero… ¿qué pasa si queremos definir explícitamente el contrato del objeto?

La forma no recomendada de tipar objetos

Podríamos hacer algo así:

const user: {
  name: string
  age: number
} = {
  name: 'midudev',
  age: 30
}

Funciona. Pero tiene un problema claro:

Si tienes más objetos del mismo tipo, vas a repetir esta estructura una y otra vez.

Y cuando empiezas a repetir estructuras… es señal de que necesitas un contrato reutilizable.

La solución profesional: type alias

Creamos un tipo reutilizable:

type User = {
  name: string
  age: number
}

Ahora podemos usarlo en cualquier sitio:

const user: User = { name: 'midudev', age: 30 }
const anotherUser: User = { name: 'Ada', age: 36 }

Lo interesante es que este tipo:

  • Puede usarse en parámetros de funciones
  • Puede usarse como tipo de retorno
  • Puede exportarse a otros archivos

Reutilizar tipos entre archivos

En proyectos reales, lo habitual es crear un archivo dedicado, por ejemplo types.ts.

Exportamos el tipo:

export type User = {
  name: string
  age: number
}

Y lo importamos así:

import type { User } from './types'

Fíjate en el import type. Es la forma correcta cuando solo estás importando un tipo.

Esto permite reutilizar contratos en todo el proyecto sin repetir código.

Propiedades opcionales

Imaginemos que algunos usuarios tienen email y otros no.

Podemos definirlo así:

type User = {
  name: string
  age: number
  email?: string
}

El ? indica que la propiedad es opcional.

Muy importante:

  • Si el objeto no tiene email, no pasa nada.
  • Si lo tiene, debe ser string.

TypeScript seguirá validando el tipo cuando exista.

Propiedades readonly

A veces queremos que ciertas propiedades no puedan modificarse.

type User = {
  readonly name: string
  age: number
}

Ahora, si alguien intenta hacer:

user.name = 'Miguel' // Error: no se puede asignar a 'name' porque es de solo lectura

TypeScript dará un error en tiempo de compilación.

Esto evita muchos bugs antes de ejecutar el código.

readonly vs const vs Object.freeze

Aquí hay una diferencia clave:

  • readonly → protección en tiempo de compilación (TypeScript)
  • const → impide reasignar la variable, pero no evita modificar propiedades internas
  • Object.freeze() → protección en tiempo de ejecución (JavaScript)

Ejemplo:

const user = Object.freeze({
  name: 'midudev',
  age: 30
})

user.name = 'otro' // No da error en TS, pero en runtime no se modifica

Es importante entender esta diferencia:

  • TypeScript protege antes de ejecutar
  • JavaScript protege cuando el código ya está corriendo

Caso práctico: configuraciones

readonly es especialmente útil en:

  • Configuraciones
  • API Keys
  • Valores que no deberían mutar nunca

Por ejemplo:

type Configuration = {
  readonly apiKey: string
  readonly baseUrl: string
}

Así evitamos modificaciones accidentales que podrían romper la aplicación.

Lo que hemos visto

  • Cómo funciona la inferencia en objetos
  • Por qué tipar inline no escala bien
  • Cómo usar type para crear contratos reutilizables
  • Cómo importar y exportar tipos con import type
  • Propiedades opcionales con ?
  • Propiedades de solo lectura con readonly
  • Diferencia entre protección en compilación y en ejecución

Entender bien los objetos y sus contratos es fundamental para escribir TypeScript mantenible, escalable y seguro.