instanceof y las guardas

instanceof es una palabra clave de JavaScript que hereda TypeScript que permite comprobar si un objeto es de una clase concreta. Para comprobaciones más complejas que permitan distinguir si una variable es de un tipo u otro, TypeScript tiene las guardas.

En TypeScript, cuando queremos verificar el tipo de una variable, contamos con herramientas que nos permiten hacer comprobaciones en tiempo de ejecución para asegurarnos de que estamos trabajando con el tipo correcto. Dos de las técnicas más importantes para esto son el uso de la palabra clave instanceof y las funciones conocidas como guardas de tipo o type guards.

Primero, hablemos de instanceof. Esta palabra clave proviene de JavaScript y nos permite comprobar si un objeto ha sido creado a partir de un constructor o clase específica. Por ejemplo, si tenemos una variable que es una instancia de la clase Date, podemos usar fecha instanceof Date para verificarlo. Esto funciona porque en JavaScript, las clases se implementan mediante funciones constructoras y prototipos, lo que permite esta comprobación en tiempo de ejecución.

Sin embargo, instanceof tiene una limitación importante: no funciona con interfaces. Las interfaces en TypeScript son un concepto que solo existe en tiempo de compilación y no se traduce a código JavaScript. Por lo tanto, no hay forma de comprobar en tiempo de ejecución si un objeto implementa una interfaz usando instanceof. Esto significa que instanceof solo es útil para clases y no para interfaces.

Entonces, ¿cómo podemos verificar tipos cuando trabajamos con interfaces? Aquí es donde entran en juego las guardas de tipo. Una guarda de tipo es una función que devuelve un valor booleano y que tiene una firma especial que indica a TypeScript que, si la función devuelve true, el parámetro es de un tipo específico. Esto se logra con la sintaxis parametro is Tipo.

Por ejemplo, imaginemos que tenemos una interfaz Cuadrado con ciertas propiedades como lado y un método pintar. Podemos crear una función guarda que reciba un parámetro de tipo any y que compruebe si ese objeto tiene las propiedades y métodos que esperamos de un Cuadrado. Si la función devuelve true, TypeScript entenderá que dentro del bloque donde se llamó a la función, el parámetro es un Cuadrado, y nos permitirá acceder a sus propiedades sin necesidad de hacer un casteo manual.

Este enfoque es especialmente útil cuando recibimos datos de tipo any o cuando no podemos usar instanceof porque estamos trabajando con interfaces. La guarda de tipo nos permite hacer comprobaciones en tiempo de ejecución basadas en la estructura del objeto, lo que se conoce como duck typing.

Veamos un ejemplo práctico de una guarda de tipo para un Cuadrado:

interface Cuadrado {
  lado: number;
  pintar(): void;
}

function esCuadrado(x: any): x is Cuadrado {
  return x !== null &&
         typeof x === 'object' &&
         'lado' in x &&
         typeof x.lado === 'number' &&
         'pintar' in x &&
         typeof x.pintar === 'function';
}

En esta función, comprobamos que x no sea nulo, que sea un objeto, que tenga la propiedad lado de tipo número y que tenga un método pintar. Si todas estas condiciones se cumplen, la función devuelve true y TypeScript sabe que x es un Cuadrado.

Luego, al usar esta función, podemos hacer algo así:

const figura: any = obtenerFigura();

if (esCuadrado(figura)) {
  // Aquí TypeScript sabe que figura es un Cuadrado
  figura.pintar();
  console.log(`El lado mide ${figura.lado}`);
}

De esta forma, evitamos tener que hacer casteos manuales y ganamos seguridad en el tipo de datos con los que trabajamos.

Además, podemos crear guardas similares para otras interfaces, como Triangulo, comprobando las propiedades específicas que definen ese tipo. Esto nos permite manejar tipos compuestos y discriminados de manera más segura y elegante.

En resumen, mientras que instanceof es útil para comprobar tipos basados en clases, las guardas de tipo nos ofrecen una forma avanzada y flexible de verificar tipos basados en interfaces, haciendo comprobaciones en tiempo de ejecución que enriquecen la experiencia de tipado en TypeScript.

Lista de reproducción
  1. 1
    Temporada 1
    5 minutos
  2. 2
    ¿Qué es TypeScript?
    11 minutos
  3. 3
    Instalando TypeScript
    8 minutos
  4. 4
    Compilando un Hola Mundo sencillo
    7 minutos
  5. 5
    Hola Mundo pero con tipos
    10 minutos
  6. 6
    Tipos: tipos primitivos
    12 minutos
  7. 7
    Tipos: tipos especiales (any, null, ...)
    10 minutos
  8. 8
    Tipos: arrays y tuplas
    11 minutos
  9. 9
    Tipos: objetos
    7 minutos
  10. 10
    Funciones: lo básico
    9 minutos
  11. 11
    Funciones: tipando funciones
    9 minutos
  12. 12
    Clases: introducción a las clases
    9 minutos
  13. 13
    Clases: creando una clase
    10 minutos
  14. 14
    Clases: modificador private
    8 minutos
  15. 15
    Clases: modificador readonly
    3 minutos
  16. 16
    Clases: Atributos virtuales con getters y setters
    10 minutos
  17. 17
    Clases: herencia
    9 minutos
  18. 18
    Clases: modificadores abstract y protected
    8 minutos
  19. 19
    Tipos alias
    6 minutos
  20. 20
    Tipos literales
    5 minutos
  21. 21
    Uniones de tipos
    7 minutos
  22. 22
    Uniones discriminantes
    7 minutos
  23. 23
    Intersecciones de tipos
    5 minutos
  24. 24
    Interfaces: introducción
    7 minutos
  25. 25
    Interfaces: modificadores y funciones
    9 minutos
  26. 26
    Interfaces: usándolas con clases
    8 minutos
  27. 27
    Interfaces: herencia de interfaces
    8 minutos
  28. 28
    Interfaces: interfaces indizadas
    5 minutos
  29. 29
    Interfaces: funciones y tipos híbridos
    5 minutos
  30. 30
    ¿Qué diferencia hay entre interfaces y tipos? (2020)
    8 minutos
  31. 31
    Casteos con as
    6 minutos
  32. 32
    instanceof y las guardas
    9 minutos
  33. 33
    Tipos enumerados
    8 minutos
  34. 34
    Valores avanzados para enumerados
    7 minutos
  35. 35
    Enumerados con valores computados
    6 minutos
  36. 36
    Genéricos en tipos
    8 minutos
  37. 37
    Múltiples genéricos y buenas prácticas
    5 minutos
  38. 38
    Genéricos en funciones
    8 minutos
  39. 39
    Genéricos con restricciones
    6 minutos
  40. 40
    Tipos de utilidad
    3 minutos
  41. 41
    Exportando módulos
    9 minutos
  42. 42
    Importando módulos
    7 minutos
  43. 43
    Export default e import asterisco
    6 minutos
  44. 44
    tsconfig
    7 minutos
  45. 45
    Módulos desde NPM
    7 minutos
  46. 46
    Arroba types y los .d.ts
    8 minutos
  47. 47
    Ejemplo (1): creando una API REST simple en TypeScript
    11 minutos
  48. 48
    Ejemplo (2): montando un servidor Express
    8 minutos
  49. 49
    Ejemplo (3): haciendo las funciones de control de datos
    11 minutos
  50. 50
    Ejemplo (4): conectando todas las piezas
    7 minutos