Inicio > Cursos > TypeScript > Type Guards y Narrowing
TypeScriptTypeScript BásicoLección 5 de 18

Type Guards y Narrowing

Narrowing es uno de los poderes más inteligentes de TypeScript. Cuando tienes una variable de tipo string | number y entras a un if (typeof valor === "string"), TypeScript sabe automáticamente que dentro de ese bloque la variable es string. No tienes que hacer un cast manual.

TypeScript analiza el flujo del código y reduce (narrow) el tipo en cada rama, dándote exactamente las propiedades y métodos disponibles según el tipo en ese punto.

TypeScript entiende varios operadores para hacer narrowing: typeof para primitivos, instanceof para clases, el operador in para verificar si una propiedad existe en un objeto, y comparaciones de igualdad (=== null, === undefined). Cuando ninguno de estos es suficiente, puedes crear type predicates personalizados: funciones que retornan "valor is Tipo" y le indican a TypeScript que si la función retorna true, entonces la variable es de ese tipo específico.

// typeof narrowing
function procesar(valor: string | number) {
  if (typeof valor === "string") {
    return valor.toUpperCase(); // TypeScript sabe: string
  }
  return valor.toFixed(2); // TypeScript sabe: number
}

// instanceof narrowing
function manejarError(e: unknown) {
  if (e instanceof Error) {
    console.error(e.message); // TypeScript sabe: Error
  } else if (typeof e === "string") {
    console.error(e);
  } else {
    console.error("Error desconocido");
  }
}

// in narrowing (propiedad existe en objeto)
interface Perro { ladrar(): void; }
interface Gato { maullar(): void; }
function hacerSonido(animal: Perro | Gato) {
  if ("ladrar" in animal) {
    animal.ladrar(); // TypeScript sabe: Perro
  } else {
    animal.maullar(); // TypeScript sabe: Gato
  }
}

// Type predicate — función que hace narrowing
function esString(valor: unknown): valor is string {
  return typeof valor === "string";
}
function esUsuario(obj: unknown): obj is Usuario {
  return typeof obj === "object" && obj !== null && "id" in obj && "email" in obj;
}

// Exhaustiveness check con never
type Figura = { tipo: "circulo"; radio: number } | { tipo: "rect"; ancho: number; alto: number };
function area(f: Figura): number {
  switch (f.tipo) {
    case "circulo": return Math.PI * f.radio ** 2;
    case "rect": return f.ancho * f.alto;
    default: const _exhaustive: never = f; return _exhaustive;
  }
}
Consejo✅ El exhaustiveness check con never es una técnica poderosa: si agregas un nuevo case a un union y olvidas manejarlo en el switch, TypeScript lanzará un error de compilación.
← Funciones TipadasClases en TypeScript →

Practica esta lección

Resuelve los ejercicios del curso de TypeScript en la app, gratis y con corrección automática.

Empezar a practicar