En TypeScript, las guardias de tipo (type guards) son una técnica que permite a los desarrolladores verificar el tipo de una variable en tiempo de ejecución. Esto es especialmente útil cuando se trabaja con tipos de unión, ya que permite a TypeScript inferir el tipo específico de una variable dentro de un bloque de código.

Conceptos Clave

  1. Guardias de Tipo con typeof: Utilizado para verificar tipos primitivos como string, number, boolean, etc.
  2. Guardias de Tipo con instanceof: Utilizado para verificar si un objeto es una instancia de una clase específica.
  3. Guardias de Tipo Personalizadas: Funciones que devuelven un predicado de tipo, permitiendo verificaciones más complejas.

Guardias de Tipo con typeof

El operador typeof se utiliza para verificar el tipo de una variable en tiempo de ejecución. Es útil para tipos primitivos.

function padLeft(value: string, padding: string | number) {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
    throw new Error(`Expected string or number, got '${typeof padding}'.`);
}

// Ejemplo de uso
console.log(padLeft("Hello", 4)); // "    Hello"
console.log(padLeft("Hello", ">>")); // ">>Hello"

En este ejemplo, typeof padding se utiliza para determinar si padding es un number o un string, y se maneja cada caso en consecuencia.

Guardias de Tipo con instanceof

El operador instanceof se utiliza para verificar si un objeto es una instancia de una clase específica.

class Bird {
    fly() {
        console.log("Flying");
    }
}

class Fish {
    swim() {
        console.log("Swimming");
    }
}

type Pet = Bird | Fish;

function move(pet: Pet) {
    if (pet instanceof Bird) {
        pet.fly();
    } else if (pet instanceof Fish) {
        pet.swim();
    }
}

// Ejemplo de uso
const myBird = new Bird();
const myFish = new Fish();

move(myBird); // "Flying"
move(myFish); // "Swimming"

En este ejemplo, instanceof se utiliza para verificar si pet es una instancia de Bird o Fish, y se llama al método correspondiente.

Guardias de Tipo Personalizadas

Las guardias de tipo personalizadas son funciones que devuelven un predicado de tipo. Estas funciones permiten verificaciones más complejas y específicas.

interface Cat {
    meow(): void;
}

interface Dog {
    bark(): void;
}

function isCat(pet: Cat | Dog): pet is Cat {
    return (pet as Cat).meow !== undefined;
}

function makeSound(pet: Cat | Dog) {
    if (isCat(pet)) {
        pet.meow();
    } else {
        pet.bark();
    }
}

// Ejemplo de uso
const myCat: Cat = { meow: () => console.log("Meow") };
const myDog: Dog = { bark: () => console.log("Bark") };

makeSound(myCat); // "Meow"
makeSound(myDog); // "Bark"

En este ejemplo, isCat es una guardia de tipo personalizada que verifica si pet es un Cat. La función makeSound utiliza esta guardia para determinar el tipo de pet y llamar al método correspondiente.

Ejercicio Práctico

Ejercicio

Crea una función getArea que acepte un parámetro de tipo Shape, que puede ser un Circle o un Rectangle. La función debe devolver el área de la forma. Utiliza guardias de tipo para determinar el tipo de la forma y calcular el área correctamente.

interface Circle {
    kind: "circle";
    radius: number;
}

interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}

type Shape = Circle | Rectangle;

function getArea(shape: Shape): number {
    // Implementa la función aquí
}

// Ejemplo de uso
const myCircle: Circle = { kind: "circle", radius: 10 };
const myRectangle: Rectangle = { kind: "rectangle", width: 5, height: 10 };

console.log(getArea(myCircle)); // 314.159...
console.log(getArea(myRectangle)); // 50

Solución

function getArea(shape: Shape): number {
    if (shape.kind === "circle") {
        return Math.PI * shape.radius * shape.radius;
    } else if (shape.kind === "rectangle") {
        return shape.width * shape.height;
    }
    throw new Error("Unknown shape");
}

// Ejemplo de uso
const myCircle: Circle = { kind: "circle", radius: 10 };
const myRectangle: Rectangle = { kind: "rectangle", width: 5, height: 10 };

console.log(getArea(myCircle)); // 314.159...
console.log(getArea(myRectangle)); // 50

Conclusión

Las guardias de tipo son una herramienta poderosa en TypeScript que permite a los desarrolladores manejar tipos de manera segura y eficiente en tiempo de ejecución. Al utilizar typeof, instanceof y guardias de tipo personalizadas, puedes escribir código más robusto y menos propenso a errores. En el siguiente módulo, exploraremos los tipos mapeados, que te permitirán transformar tipos de manera más avanzada y flexible.

© Copyright 2024. Todos los derechos reservados