Cómo verificar el tipo de clase en TypeScript: de principiante a experto
\n\n¿Alguna vez has escrito en TypeScript, has recibido un objeto de tipo desconocido y has pensado: "¿Y tú quién eres, exactamente?"? Esta pregunta atormenta a miles de desarrolladores — no en vano el tema class type check in TypeScript ha acumulado cientos de miles de visitas en Stack Overflow. Y hoy, de una vez por todas, entenderemos cómo verificar correctamente los tipos de clases en TypeScript.
\n\nEn este artículo aprenderás:
\n- \n
- Por qué
typeofno funciona con clases \n - Cómo usar
instanceofcomo una navaja suiza \n - Qué son los type guards y cómo salvan tu código \n
- Cómo escribir tu propia verificación de tipo con
is\n - Ejemplos reales de la práctica \n
¡Allá vamos!
\n\nEl problema: ¿por qué typeof es inútil aquí?
\n\nEn JavaScript existe el operador typeof, que funciona muy bien con primitivos:
typeof "hello" // "string"\ntypeof 42 // "number"\ntypeof true // "boolean"\n\nPero cuando se trata de clases, typeof falla:
class Dog {}\nclass Cat {}\n\nconst pet = new Dog();\n\ntypeof pet; // "object" — ¡inútil!\ntypeof Dog; // "function" — tampoco sirve\n\n¿Por qué? Porque las clases en JavaScript son simplemente azúcar sintáctico sobre funciones constructoras. typeof solo ve "objeto" o "función", pero no distingue de qué clase se trata.
Aquí entra en escena el class type check in TypeScript — todo un arsenal de herramientas que te ayudará a determinar exactamente con qué instancia de clase estás tratando.
\n\nMétodo 1: instanceof — tu principal aliado
\n\nLa forma más directa y clara de verificar el tipo de clase es el operador instanceof. Verifica si la clase está en la cadena de prototipos del objeto:
class Animal {\n name: string;\n constructor(name: string) {\n this.name = name;\n }\n}\n\nclass Dog extends Animal {\n bark() {\n console.log("Woof!");\n }\n}\n\nclass Cat extends Animal {\n meow() {\n console.log("Meow!");\n }\n}\n\nfunction handleAnimal(animal: Animal) {\n if (animal instanceof Dog) {\n // TypeScript sabe que animal es un Dog\n animal.bark();\n } else if (animal instanceof Cat) {\n animal.meow();\n } else {\n console.log(`Unknown animal: ${animal.name}`);\n }\n}\n\nconst rex = new Dog("Rex");\nhandleAnimal(rex); // "Woof!"\n\nObserva: después de la verificación animal instanceof Dog, TypeScript estrecha automáticamente el tipo (type narrowing) y permite llamar a los métodos de Dog sin errores. Esta es la magia de los type guards — protectores de tipos incorporados.
¿Cuándo no funciona instanceof?
\n- \n
- Al trabajar con diferentes ventanas/frames (diferentes objetos globales) \n
- Si las clases están definidas en diferentes módulos con versiones distintas \n
- Al verificar interfaces (no existen en tiempo de ejecución) \n
Método 2: Type guards personalizados con el operador is
\n\nA veces instanceof no es suficiente. Por ejemplo, quieres verificar no solo la clase, sino también condiciones adicionales. Aquí es donde entran en juego los type guards personalizados con la palabra clave is:
interface Bird {\n fly(): void;\n layEggs(): void;\n}\n\ninterface Fish {\n swim(): void;\n layEggs(): void;\n}\n\nfunction isFish(pet: Bird | Fish): pet is Fish {\n return (pet as Fish).swim !== undefined;\n}\n\nfunction move(pet: Bird | Fish) {\n if (isFish(pet)) {\n // TypeScript sabe: pet es un Fish\n pet.swim();\n } else {\n pet.fly();\n }\n}\n\nObserva la sintaxis: pet is Fish en el tipo de retorno. Esto le dice a TypeScript: "Si esta función devuelve true, entonces el parámetro pet es un Fish". Ahora TypeScript estrechará el tipo en todas partes donde uses