TypeScript Medio · Teoría

Comprende antes de memorizar

22 lecciones originales con ejemplos breves, puntos clave y referencias para profundizar.

01

Funciones genéricas

Un parámetro de tipo conserva relaciones entre entradas y salidas sin sustituirlas por any. TypeScript suele inferirlo desde los argumentos.

Ejemplo
function primero<T>(valores: readonly T[]): T | undefined { return valores[0]; }

Puntos importantes

  • T representa una relación, no un tipo concreto fijo.
  • Expón sólo los parámetros que aportan información al contrato.
Practicar este concepto
03

Valores predeterminados genéricos

Un parámetro genérico puede tener un tipo predeterminado cuando la inferencia y los argumentos explícitos no aportan otro.

Ejemplo
type Resultado<T = string> = { valor: T; correcto: boolean };

Puntos importantes

  • Los parámetros obligatorios preceden a los predeterminados.
  • El default debe satisfacer su constraint.
05

typeof en posiciones de tipo

En una posición de tipo, typeof obtiene el tipo estático de un valor declarado. No es la misma operación que el typeof de runtime usado para narrowing.

Ejemplo
const configuracion = { modo: "seguro", intentos: 3 };
type Configuracion = typeof configuracion;

Puntos importantes

  • Sólo consulta identificadores y propiedades accesibles, no ejecuta expresiones arbitrarias.
  • Combina bien con keyof y indexed access.
07

Intersecciones

A & B exige satisfacer simultáneamente ambas estructuras. No es una operación que mezcle objetos en runtime.

Ejemplo
type ConId = { id: string };
type Auditable = { actualizado: number };
type Registro = ConId & Auditable;

Puntos importantes

  • Propiedades incompatibles pueden producir never.
  • La construcción del valor sigue siendo responsabilidad del código.
09

never y exhaustividad

never representa un estado imposible. Asignar la variante restante a never hace que una nueva alternativa rompa el build hasta tratarla.

Ejemplo
function imposible(valor: never): never { throw new Error(String(valor)); }

Puntos importantes

  • Una función que siempre lanza puede devolver never.
  • La comprobación exhaustiva protege evoluciones de una unión.
Practicar este concepto
10

Type predicates

Una función que retorna valor is Tipo comunica al checker un narrowing probado por lógica de runtime escrita por el programa.

Ejemplo
function esTexto(valor: unknown): valor is string { return typeof valor === "string"; }

Puntos importantes

  • El predicado debe decir la verdad; TypeScript no inspecciona su implementación semántica.
  • Acepta unknown en fronteras no confiables.
Practicar este concepto
11

Assertion functions

Una firma asserts condicion o asserts valor is Tipo indica que el retorno normal garantiza una condición; el fallo debe interrumpir el flujo.

Ejemplo
function exigirTexto(valor: unknown): asserts valor is string { if (typeof valor !== "string") throw new Error("texto esperado"); }

Puntos importantes

  • Si la función retorna sin validar, el checker confiará igualmente.
  • Son útiles al centralizar validaciones de invariantes.
12

Sobrecargas

Las firmas de overload describen llamadas públicas y una implementación compatible las resuelve. La firma de implementación no es directamente invocable desde fuera.

Ejemplo
function convertir(valor: string): number;
function convertir(valor: number): string;
function convertir(valor: string | number) { return typeof valor === "string" ? Number(valor) : String(valor); }

Puntos importantes

  • Mantén pocas firmas distinguibles.
  • Prefiere uniones cuando entrada y salida no necesitan correlación especial.
Practicar este concepto
13

Clases genéricas

Una clase genérica relaciona el estado y los métodos de cada instancia con un tipo elegido o inferido.

Ejemplo
class Caja<T> { constructor(public valor: T) {} map<U>(f: (valor: T) => U): Caja<U> { return new Caja(f(this.valor)); } }

Puntos importantes

  • Los miembros estáticos no pueden usar el parámetro de instancia.
  • No añadas T si la clase no conserva ninguna relación.
Practicar este concepto
14

Clases abstractas

Una clase abstracta puede compartir implementación y exigir miembros a subclases, pero no puede instanciarse directamente.

Ejemplo
abstract class Figura { abstract area(): number; describir() { return `Área: ${this.area()}`; } }

Puntos importantes

  • abstract es una restricción de TypeScript.
  • Una interface desacopla mejor cuando no necesitas implementación base.
16

Mapped types

Un mapped type recorre keyof para producir propiedades y puede añadir o retirar readonly y opcionalidad.

Ejemplo
type Opcional<T> = { [K in keyof T]?: T[K] };

Puntos importantes

  • K representa cada clave durante la transformación.
  • Los modificadores + y - controlan readonly y ?.
18

Template literal types

Los template literal types forman cadenas a partir de literales y uniones, útiles para eventos y claves derivadas.

Ejemplo
type Evento = `usuario:${"creado" | "eliminado"}`;

Puntos importantes

  • Las uniones se expanden combinatoriamente.
  • No reemplazan validación de texto externo.
19

Promise y Awaited

Promise<T> describe el resultado futuro y Awaited<T> desenvuelve recursivamente promesas y thenables según la semántica de await.

Ejemplo
async function cargar(): Promise<number> { return 7; }
type Dato = Awaited<ReturnType<typeof cargar>>;

Puntos importantes

  • async siempre devuelve una Promise.
  • Los rechazos no aparecen en el parámetro T.
20

Compatibilidad estructural

Un valor es compatible si ofrece al menos los miembros requeridos con tipos compatibles. La procedencia nominal no suele importar.

Ejemplo
interface Nombrado { nombre: string }
const completo = { nombre: "Ada", edad: 36 };
const breve: Nombrado = completo;

Puntos importantes

  • Las variables pueden tener propiedades adicionales.
  • La comparación de funciones depende de parámetros, retorno y strictFunctionTypes.
22

import type, export type y opciones

import type y export type hacen explícitas dependencias borradas al emitir. verbatimModuleSyntax preserva la intención; module/moduleResolution deben ajustarse al host real.

Ejemplo
import type { Usuario } from "./modelos";
export type { Usuario };

Puntos importantes

  • Un import type no puede usarse como valor.
  • Opciones como noUncheckedIndexedAccess refuerzan contratos más allá de strict.