Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/midudev/jscamp/llms.txt

Use this file to discover all available pages before exploring further.

Esta es una referencia rápida de los conceptos de TypeScript cubiertos en el módulo 06 de JSCamp, organizada por tema. Expande cada sección para ver ejemplos de código extraídos directamente de los archivos del bootcamp. Úsala como cheatsheet mientras trabajas en los módulos 06, 07 y 08.
TypeScript es un superset de JavaScript. Todo el código JS válido también es TS válido. El compilador te avisa de los errores antes de ejecutar el código.

TypeScript añade anotaciones de tipo sobre los primitivos de JavaScript. Puedes declarar tipos explícitamente o dejar que TypeScript los infiera automáticamente.
// ── Inferencia automática ──────────────────────────
const nombre = "midudev"        // inferido: string
const ciudad = "Madrid"         // inferido como literal: "Madrid" (const)
let pais = "España"             // inferido: string (let → amplio)

// ── Anotaciones explícitas ─────────────────────────
const vacio: string = ""
let isActive: boolean = true
let age: number | null = null   // unión con null

// ── Otros primitivos ──────────────────────────────
const numeroGrande: bigint = 9007199254741991n
const id: symbol = Symbol("id")

// ── Literales como tipos ──────────────────────────
type Direction = 'up' | 'down' | 'left' | 'right'
type Level     = 1 | 2 | 3 | 4 | 5

// ── Type aliases ──────────────────────────────────
type UserId = {
  readonly id: string | number
}

type User = {
  readonly name: string
  readonly age: number
  email?: string        // propiedad opcional
  company?: Company     // propiedad opcional anidada
  role: "admin" | "user" | "editor"
}

// ── Intersección de tipos ─────────────────────────
type UserWithBirthdate = { birthdate: Date }
type UserEntity = User & UserId & UserWithBirthdate
Con const, TypeScript infiere el tipo literal más estrecho ("Madrid"). Con let, infiere el tipo amplio (string). Usa as const para forzar inferencia literal en let.
Arrays almacenan colecciones de elementos del mismo tipo. Tuplas son arrays de longitud fija con tipos específicos por posición.
// ── Arrays: dos sintaxis equivalentes ────────────
const numeros: number[] = [1, 2, 3, 4, 5]
numeros.push(6)

const numerosAlt: Array<number> = [10, 20, 30]
numerosAlt.push(40)

// ── Arrays de tipos mixtos (unión) ────────────────
const mixto: (string | number)[] = [1, "dos", 3, "cuatro"]
const conOpcionales: (string | undefined)[] = ["uno", undefined, "tres"]

// ── Tuplas básicas ────────────────────────────────
const persona: [string, number] = ["midudev", 30]
const [personaName, personaAge] = persona  // destructuring

// ── Tuplas con etiquetas (named tuples) ──────────
type Coordenadas = [latitude: number, longitude: number]
const [lat, lon]: Coordenadas = [40.4168, -3.7038]

type RGB = [number, number, number]
const rojo: RGB   = [255, 0, 0]
const verde: RGB  = [0, 255, 0]
const azul: RGB   = [0, 0, 255]

// ── Tuplas readonly ───────────────────────────────
type Config = readonly [server: string, port: number, useSSL: boolean]
const dbConfig: Config = ["localhost", 5432, true]

// ── Tuplas con REST elements ──────────────────────
type StringYMuchosNumeros = [string, ...number[]]
const [text, first, ...rest]: StringYMuchosNumeros = ["hola", 1, 2, 3, 4]

// ── Patrón React useState ─────────────────────────
type EstadoContador = [value: number, update: (v: number) => void]
Estos cuatro tipos especiales controlan el comportamiento del sistema de tipos en casos límite.
// ── ANY: desactiva la comprobación de tipos ───────
// ❌ Evitar siempre que sea posible
let cualquierCosa: any = "hola"
cualquierCosa = 42
cualquierCosa = true
const result = cualquierCosa + 8  // no hay error, pero es peligroso

// ── UNKNOWN: alternativa segura a any ────────────
// ✅ Acepta cualquier valor pero obliga a verificar antes de usar
let valorDesconocido: unknown = "hola"
valorDesconocido = 42

// Requiere type narrowing para usarlo:
if (typeof valorDesconocido === 'number') {
  const resultadoSeguro = valorDesconocido + 8   // ✅ OK
}
if (typeof valorDesconocido === 'string') {
  console.log(valorDesconocido.toUpperCase())    // ✅ OK
}

// ── VOID: funciones que no retornan valor útil ───
function saludar(): void {
  console.log("Hola!")
}

function logError(errorMessage: string): void {
  if (errorMessage.length === 0) return undefined
  console.error("Error:", errorMessage)
}

// ── NEVER: el tipo imposible ─────────────────────
// Para funciones que nunca terminan o siempre lanzan error
function bucleInfinito(): never {
  while (true) { /* ... */ }
}

function throwError(message: string): never {
  throw new Error(message)
}

// NEVER en exhaustiveness checking (discriminated unions):
function revisarValor(x: number | string) {
  if (typeof x === 'number') {
    console.log("Número:", x)
  } else if (typeof x === 'string') {
    console.log("String:", x)
  } else {
    // Aquí x es de tipo 'never': hemos cubierto todos los casos
    throwError("Tipo no soportado")
  }
}
TipoAceptaPermite usar sin verificarCuándo usarlo
anyTodo✅ Sí (sin seguridad)❌ Nunca (migración puntual)
unknownTodo❌ No✅ Datos externos, errores de catch
voidundefinedN/A✅ Funciones sin retorno
neverNadaN/A✅ Funciones que no terminan o lanzan
TypeScript permite tipar parámetros, valores de retorno y hasta el tipo completo de una función.
// ── Parámetros y retorno explícitos ───────────────
function sumar(a: number, b: number): number {
  return a + b
}

const multiplicar = (a: number, b: number): number => a * b
const dividir     = (a: number, b: number): number => a / b

// ── Parámetros opcionales (?) ─────────────────────
function saludar(nombre: string, apellido?: string): string {
  if (apellido) return `Hola, ${nombre} ${apellido}`
  return `Hola, ${nombre}`
}

// ── Parámetros con valor por defecto ─────────────
function crearUsuario(nombre: string, rol: string = "admin") {
  return { nombre, rol }
}

// ── Rest parameters ───────────────────────────────
function sumarNumeros(...numeros: number[]): number {
  return numeros.reduce((acc, curr) => acc + curr, 0)
}
sumarNumeros(1, 2)
sumarNumeros(1, 2, 3, 4, 5)

// ── Tipo de función (Function Types) ─────────────
type OperacionMatematica = (a: number, b: number) => number

const division: OperacionMatematica = (a, b) => a / b
const resta:    OperacionMatematica = (a, b) => a - b

// ── Callbacks tipados ─────────────────────────────
function procesarArray(
  arr: number[],
  callback: (item: number) => string
): string[] {
  return arr.map(callback)
}

// ── Overloads ─────────────────────────────────────
function formatId(id: number): string
function formatId(id: string): string
function formatId(id: number | string): string {
  return `ID-${id}`
}
El type narrowing (estrechamiento de tipos) permite reducir un tipo amplio a uno más específico usando comprobaciones en tiempo de ejecución. TypeScript entiende estas comprobaciones y ajusta el tipo automáticamente dentro de cada rama.
// ── typeof narrowing ──────────────────────────────
function procesar(valor: number | string) {
  if (typeof valor === 'number') {
    // valor: number aquí
    console.log(valor.toFixed(2))
  } else {
    // valor: string aquí
    console.log(valor.toUpperCase())
  }
}

// ── Nullish narrowing ─────────────────────────────
function imprimirMensaje(mensaje: string | null | undefined) {
  if (mensaje) {
    console.log(mensaje.toUpperCase())  // mensaje: string (no null/undefined)
  }
}

// ── in narrowing (discriminated union) ───────────
type Pez    = { nadar: () => void; nombre: string }
type Pajaro = { volar: () => void; nombre: string }
type Perro  = { ladrar: () => void; nombre: string }
type Animal = Pez | Pajaro | Perro

function moverAnimal(animal: Animal) {
  if ('nadar' in animal) {
    animal.nadar()     // animal: Pez
  } else if ('volar' in animal) {
    animal.volar()     // animal: Pajaro
  } else {
    animal.ladrar()    // animal: Perro
  }
}

// ── instanceof narrowing ──────────────────────────
function formatDate(value: Date | string): string {
  if (value instanceof Date) {
    return value.toUTCString()   // value: Date
  }
  return new Date(value).toUTCString()  // value: string
}

// ── Discriminated unions con literal type ─────────
type JobData = {
  modality: "remote" | "onsite" | "hybrid"
  level:    "junior" | "mid" | "senior"
  technology: string[]
}

function describir(modality: JobData["modality"]): string {
  switch (modality) {
    case "remote":  return "100% remoto"
    case "onsite":  return "Presencial"
    case "hybrid":  return "Híbrido"
  }
}
Los discriminated unions combinan un campo literal discriminador (p. ej. type: "success" | "error") con datos específicos por variante. Son la alternativa tipada a los instanceof con clases.
Tanto interface como type definen la forma de un objeto. La elección depende del caso de uso.
// ══════════════════════════════════════════════════
// INTERFACES
// ══════════════════════════════════════════════════

interface Persona {
  readonly name: string
  readonly age: number
}

interface Identificable {
  id: `user-${number}`   // template literal type
}

// extends: herencia entre interfaces
interface User extends Persona, Identificable {
  email?: string
  role: "admin" | "user" | "editor"
  saludar: () => string
  login(): boolean
}

interface Admin extends User {
  adminLevel: number
  accessAllAreas: boolean
}

// Declaration merging (solo interfaces):
// TypeScript fusiona las dos declaraciones automáticamente
interface Hero { nombre: string }
interface Hero { poder: string  }

const hero: Hero = { nombre: "Superman", poder: "Volar" }  // ✅

// Interfaces para clases (implements)
interface MediaPlayer {
  play(): void
  pause(): void
  stop(): void
}

class Reproductor implements MediaPlayer {
  play():  void { console.log("Reproduciendo...") }
  pause(): void { console.log("Pausado") }
  stop():  void { console.log("Detenido") }
}

// ══════════════════════════════════════════════════
// TYPE ALIASES
// ══════════════════════════════════════════════════

// Uniones: solo posibles con type
type StringOrNumber = string | number
type ID = string | number | symbol

// Tipos literales
type Rol = "admin" | "user" | "editor"

// Intersección (equivalente a extends)
type UserEntity = User & Identificable & { birthdate: Date }

// Tipos de utilidad con type
type Configuration = {
  readonly apiKey: string
  readonly theme: 'dark' | 'light'
}
Diferencias clave
Característicainterfacetype
Declaration merging
Uniones (|)
Intersecciones (&)via extends✅ directo
Tipos primitivos/tuplas
implements en clases
Mapped types
Regla general: usa interface para definir la forma de objetos y contratos de clases; usa type para uniones, intersecciones, tipos de función y alias de primitivos.
Los generics permiten escribir código reutilizable que funciona con cualquier tipo, manteniendo la seguridad de tipos.
// ── Generic básico ────────────────────────────────
function identity<T>(value: T): T {
  return value
}

identity<string>("hola")   // T = string
identity<number>(42)       // T = number
identity("inferido")       // T inferido como string

// ── Generic con arrays ────────────────────────────
function firstElement<T>(arr: T[]): T | undefined {
  return arr[0]
}

const first = firstElement([1, 2, 3])  // number | undefined

// ── Generic con múltiples parámetros ─────────────
function pair<K, V>(key: K, value: V): [K, V] {
  return [key, value]
}

const p = pair("id", 42)  // [string, number]

// ── Interfaces genéricas ──────────────────────────
interface ApiResponse<T> {
  data: T
  status: number
  message: string
}

interface Repository<T> {
  getById(id: string): Promise<T>
  getAll(): Promise<T[]>
  create(item: Omit<T, "id">): Promise<T>
  update(id: string, item: Partial<T>): Promise<T>
  delete(id: string): Promise<void>
}

// ── Constraints con extends ───────────────────────
// T debe tener al menos la propiedad `id`
function getById<T extends { id: string }>(items: T[], id: string): T | undefined {
  return items.find(item => item.id === id)
}

// ── keyof constraint ─────────────────────────────
// K debe ser una clave válida de T
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]
}

// Ejemplo con el tipo Job del módulo 08:
interface Job {
  id: string
  title: string
  company: string
  location: string
}

const job: Job = { id: "1", title: "Dev", company: "Acme", location: "Madrid" }
const title    = getProperty(job, "title")    // string ✅
// const bad   = getProperty(job, "email")    // ❌ Error: "email" no es keyof Job

// ── Generic con valor por defecto ─────────────────
interface PaginatedResponse<T = unknown> {
  items: T[]
  total: number
  page: number
  pageSize: number
}
TypeScript incluye una librería de utility types que transforman tipos existentes sin tener que reescribirlos. Son fundamentales en el módulo 08 donde se usan Omit, Partial y tipos inferidos de Zod.
// Tipos de partida para los ejemplos:
interface Job {
  id: string
  title: string
  company: string
  location: string
  description: string
}
Tabla de Utility Types
Utility TypeDescripción
Partial<T>Hace todas las propiedades opcionales
Required<T>Hace todas las propiedades obligatorias
Readonly<T>Hace todas las propiedades de solo lectura
Pick<T, K>Selecciona un subconjunto de propiedades
Omit<T, K>Excluye un subconjunto de propiedades
Record<K, V>Crea un tipo objeto con claves K y valores V
Exclude<T, U>Excluye de T los miembros asignables a U
Extract<T, U>Extrae de T los miembros asignables a U
NonNullable<T>Elimina null y undefined de T
ReturnType<F>Tipo del valor de retorno de una función F
Parameters<F>Tupla con los tipos de parámetros de una función F
Awaited<T>Desenvuelve el tipo de una Promise<T>
InstanceType<C>Tipo de instancia de una clase C
Ejemplos de código
// ── Partial<T> ────────────────────────────────────
// Usado en PATCH: todos los campos opcionales para actualización parcial
type UpdateJobDTO = Partial<Job>
// Equivale a: { id?: string; title?: string; company?: string; ... }

const patch: UpdateJobDTO = { location: "Barcelona" }  // ✅ solo un campo

// ── Required<T> ───────────────────────────────────
interface Config { host?: string; port?: number }
type RequiredConfig = Required<Config>
// { host: string; port: number } — ya no son opcionales

// ── Readonly<T> ───────────────────────────────────
const frozenJob: Readonly<Job> = { id: "1", title: "Dev", company: "Acme", location: "Madrid", description: "..." }
// frozenJob.title = "Otro"  // ❌ Error: no se puede asignar

// ── Pick<T, K> ────────────────────────────────────
type JobSummary = Pick<Job, "id" | "title" | "company">
// { id: string; title: string; company: string }

// ── Omit<T, K> ────────────────────────────────────
// Usado en el módulo 08 para CreateJobDTO (sin id, lo genera la BD)
type CreateJobDTO = Omit<Job, "id">
// { title: string; company: string; location: string; description: string }

// ── Record<K, V> ─────────────────────────────────
type ModalityLabel = Record<"remote" | "onsite" | "hybrid", string>
const labels: ModalityLabel = {
  remote:  "Remoto",
  onsite:  "Presencial",
  hybrid:  "Híbrido"
}

// ── ReturnType<F> ────────────────────────────────
async function fetchJobs() {
  return [{ id: "1", title: "Dev" }]
}
type FetchJobsResult = Awaited<ReturnType<typeof fetchJobs>>
// { id: string; title: string }[]

// ── Parameters<F> ────────────────────────────────
function createJob(title: string, company: string, level: number) {}
type CreateJobParams = Parameters<typeof createJob>
// [title: string, company: string, level: number]

// ── Exclude y Extract ────────────────────────────
type Level = "junior" | "mid" | "senior"
type SeniorLevels = Extract<Level, "mid" | "senior">  // "mid" | "senior"
type NoSenior     = Exclude<Level, "senior">           // "junior" | "mid"

// ── NonNullable ───────────────────────────────────
type MaybeString = string | null | undefined
type DefiniteString = NonNullable<MaybeString>  // string

// ── Ejemplo real del módulo 08 (types.ts) ─────────
// CreateJobDTO y UpdateJobDTO se definen exactamente así:
interface FullJob {
  id: string
  title: string
  company: string
  location: string
  description: string
}

type CreateFullJobDTO = Omit<FullJob, "id">       // sin id
type UpdateFullJobDTO = Partial<CreateFullJobDTO>  // todo opcional
Zod puede inferir utility types automáticamente con z.infer<typeof schema> y schema.partial(). En el módulo 08 no hace falta definir UpdateJobDTO a mano: se obtiene de jobSchema.partial().

Build docs developers (and LLMs) love