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.

Este módulo ofrece una serie de ejercicios estructurados en 5 carpetas temáticas que cubren TypeScript de forma progresiva, desde los tipos primitivos hasta los generics avanzados y utility types. Cada archivo es un ejercicio independiente con comentarios explicativos integrados en el código.

Estructura de los Ejercicios

06-typescript/
├── 01-fundamentos/
│   ├── 00-types.ts               # Definición de tipos y type aliases complejos
│   ├── 01-primitivos.ts          # string, number, boolean, bigint, symbol
│   ├── 02-arrays.ts              # Arrays tipados con sintaxis T[] y Array<T>
│   ├── 03-objetos.ts             # Objetos con tipos importados y union types
│   ├── 04-tuplas.ts              # Tuplas: coordenadas, RGB, useState pattern
│   └── 05-any-unknown-never-void.ts  # Los tipos especiales y cuándo usarlos
├── 02-funciones/
│   ├── 01-basicos.ts             # Parámetros, retornos, rest params, Function Types
│   └── 02-type-narrowing.ts      # typeof, in operator, instanceof narrowing
├── 03-interfaces-types/
│   ├── 01-interfaces.ts          # Interfaces, herencia, declaration merging
│   └── 02-types-vs-interfaces.ts # Comparativa detallada de cuándo usar cada uno
├── 04-generics/
│   ├── 01-generics-basicos.ts    # Funciones genéricas, constraints y defaults
│   └── 02-generics-avanzados.ts  # Generics en clases, interfaces y mapped types
├── 05-utility-types/
│   ├── 01-utility-types.ts       # Partial, Required, Pick, Omit, Record, Readonly
│   └── 02-utility-types-avanzados.ts  # ReturnType, Parameters, Awaited, etc.
└── example.ts                    # Ejemplo introductorio con type narrowing básico

1. Fundamentos

Primitivos y tipos especiales

// 01-primitivos.ts

// TypeScript infiere el tipo según el contexto del token
const ciudad = "Madrid"   // tipo literal: "Madrid"
let pais = "España"       // tipo inferido: string (puede reasignarse)

// Tipos numéricos
let color = 0x09f         // hexadecimal → number
let infinito = Infinity   // también number

// Tipos especiales
const numeroGrande: bigint = 9007199254741991n
const id: symbol = Symbol("id")

let age: number | null = null  // union type con null

Arrays y tipos mixtos

// 02-arrays.ts

// Sintaxis 1: tipo[]
const numeros: number[] = [1, 2, 3, 4, 5]
numeros.push(6)

// Sintaxis 2: Array<tipo>
const numerosAlt: Array<number> = [10, 20, 30]

// Arrays con union types
const mixto: (string | number)[] = [1, "dos", 3, "cuatro"]
const arrayToFilter: (string | undefined)[] = ["uno", undefined, "tres"]

Tuplas

Las tuplas son arrays de longitud y tipos fijos en cada posición:
// 04-tuplas.ts

// Tupla básica
const persona: [string, number] = ["midudev", 30]
const [personaName, personaAge] = persona

// Casos de uso reales
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]

// Patrón useState de React
type EstadoContador = [value: number, updateFunction: (nuevoValor: number) => void]

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

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

any, unknown, never y void

// 05-any-unknown-never-void.ts

// any: desactiva TypeScript completamente — EVITAR
let cualquierCosa: any = "hola"
cualquierCosa = 42
const result = cualquierCosa + 8  // sin error, sin seguridad

// unknown: acepta cualquier valor pero exige verificación antes de usar
let valorDesconocido: unknown = "hola"
if (typeof valorDesconocido === 'number') {
  const resultadoSeguro = valorDesconocido + 8  // ✅ seguro
}

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

// never: funciones que nunca terminan o siempre lanzan error
function throwErrror(message: string): never {
  throw new Error(message)
}
TipoAceptaPermite operarUso recomendado
anyTodoSin restriccionesNunca (solo migración)
unknownTodoSolo tras narrowingDatos externos / APIs
voidundefinedNoRetorno de funciones sin valor
neverNadaNoCasos imposibles / exhaustivos

2. Funciones y Type Narrowing

Funciones básicas

// 02-funciones/01-basicos.ts

// Parámetros y retorno explícitos
function sumar(a: number, b: number): number {
  return a + b
}

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

// Parámetros 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)
}

// Function Types — tipado de funciones como valores
type OperacionMatematica = (a: number, b: number) => number

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

Type Narrowing

El type narrowing permite a TypeScript reducir un tipo amplio a uno específico mediante comprobaciones en tiempo de ejecución:
function procesar(valor: number | string) {
  if (typeof valor === 'number') {
    // TypeScript sabe que valor es number aquí
    console.log(valor.toFixed(2))
  } else {
    // TypeScript sabe que valor es string aquí
    console.log(valor.toUpperCase())
  }
}

3. Interfaces y Types

Diferencias clave

Tanto interface como type pueden describir la forma de un objeto, pero tienen diferencias importantes:
// 01-interfaces.ts

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

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

// Herencia con extends (múltiple)
interface User extends Persona, Identificable {
  email?: string
  role: "admin" | "user" | "editor"
  saludar: () => string
  login(): boolean
}

// Declaration merging: dos bloques interface se fusionan
interface Hero { nombre: string }
interface Hero { poder: string }

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

// Implementación en clases
interface MediaPlayer {
  play(): void
  pause(): void
  stop(): void
}

interface AudioPlayer {
  volumen: number
}

class Reproductor implements MediaPlayer, AudioPlayer {
  volumen: number = 50

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

Usa interface cuando…

  • Describes la forma de un objeto o clase
  • Necesitas que otras interfaces hereden de ella (extends)
  • Quieres aprovechar declaration merging (librerías)
  • Trabajas con implements en clases

Usa type alias cuando…

  • Necesitas union types (A | B) o intersection types (A & B)
  • Creas tipos literales o mapped types
  • Alias para primitivos: type ID = string | number
  • Tipos condicionales o utility types complejos

4. Generics

Los generics permiten escribir componentes reutilizables que funcionan con cualquier tipo, manteniendo la seguridad de tipos.

Generics básicos

// Función genérica: T es el parámetro de tipo
function identity<T>(value: T): T {
  return value
}

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

// Genérico con constraint: T debe tener la propiedad length
function getLength<T extends { length: number }>(item: T): number {
  return item.length
}

getLength("hola")          // ✅ string tiene length
getLength([1, 2, 3])       // ✅ array tiene length
getLength({ length: 10 })  // ✅ objeto con length

// Múltiples parámetros de tipo
function pair<T, U>(first: T, second: U): [T, U] {
  return [first, second]
}

const result = pair("nombre", 42)  // [string, number]

Generics avanzados

// Generic con valor por defecto
type ApiResponse<T = unknown> = {
  data: T
  status: number
  message: string
}

type JobResponse    = ApiResponse<Job>     // data es Job
type StringResponse = ApiResponse<string>  // data es string
type DefaultResp    = ApiResponse          // data es unknown

// Generic en interfaces
interface Repository<T> {
  findById(id: string): Promise<T | null>
  findAll(): Promise<T[]>
  create(data: Omit<T, 'id'>): Promise<T>
  update(id: string, data: Partial<T>): Promise<T | null>
  delete(id: string): Promise<boolean>
}

// Conditional types
type IsArray<T> = T extends any[] ? true : false

type CheckString = IsArray<string>    // false
type CheckArray  = IsArray<number[]>  // true

5. Utility Types

TypeScript incluye utility types que transforman tipos existentes sin redefinirlos desde cero.
interface User {
  id: string
  name: string
  email: string
  age: number
}

// Partial<T>: todos los campos opcionales
type PartialUser = Partial<User>
// { id?: string; name?: string; email?: string; age?: number }

// Required<T>: todos los campos obligatorios
type RequiredUser = Required<PartialUser>
// { id: string; name: string; email: string; age: number }

// Readonly<T>: todos los campos de solo lectura
type ReadonlyUser = Readonly<User>
// { readonly id: string; readonly name: string; ... }

Utility Types en la práctica (patrón del proyecto)

El módulo SQL usa estos utility types directamente en los DTOs de la API:
// types.ts del módulo 08-sql

export interface Job {
  id: string
  title: string
  company: string
  // ...
}

// Reutilizando la interfaz Job con Utility Types:
export type CreateJobDTO = Omit<Job, "id">          // Para POST
export type UpdateJobDTO = Partial<CreateJobDTO>     // Para PATCH

Cómo Ejecutar los Ejercicios

1

Ejecutar directamente con tsx (recomendado)

# Ejecutar un archivo TypeScript directamente
npx tsx 06-typescript/01-fundamentos/00-types.ts
npx tsx 06-typescript/02-funciones/02-type-narrowing.ts
2

Compilar con tsc

# Compilar y ejecutar
npx tsc --strict 06-typescript/01-fundamentos/01-primitivos.ts
node 06-typescript/01-fundamentos/01-primitivos.js
3

Verificar tipos sin compilar

# Solo chequeo de tipos, sin generar archivos JS
npx tsc --strict --noEmit 06-typescript/04-generics/01-generics-basicos.ts
La carpeta 06-typescript/ no tiene package.json propio. Para ejecutar los ejercicios necesitas tener tsx o tsc disponible, ya sea instalado globalmente (npm install -g tsx typescript) o usando npx como en los ejemplos anteriores. Si usas el package.json del módulo 08-sql/backend, ya tienes tsx y typescript como devDependencies y puedes usarlos desde allí.

Build docs developers (and LLMs) love