ProgramaciónDesarrollador Frontend

Explique la mecánica de la reducción de tipos (Type Narrowing) en TypeScript. ¿Cuáles son las formas de reducir los tipos de las variables y para qué se utiliza?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

La reducción de tipo (Type Narrowing) en TypeScript es el proceso mediante el cual el compilador "entiende" que en una determinada sección del código, una variable tiene un tipo más específico, basado en ciertas condiciones.

Técnicas comunes de reducción:

  • Verificación mediante el operador typeof:
function example(x: number | string) { if (typeof x === 'string') { // x: string aquí return x.toUpperCase(); } else { // x: number aquí return x.toFixed(2); } }
  • Verificación mediante instanceof (para clases):
if (dateObj instanceof Date) { // dateObj: Date }
  • Verificación de null y undefined:
function print(value?: string) { if (value != null) { // value: string console.log(value.length); } }
  • Verificación utilizando "propiedades discriminantes" (discriminant properties):
type Pet = { kind: 'dog'; woof: () => void } | { kind: 'cat'; meow: () => void }; function sound(pet: Pet) { if (pet.kind === 'dog') { pet.woof(); } else { pet.meow(); } }

TypeScript también admite funciones de predicado personalizadas:

function isString(x: unknown): x is string { return typeof x === 'string'; }

La reducción hace que las comprobaciones de tipos sean más seguras y el código más fiable.

Pregunta con trampa.

¿Se puede garantizar la reducción de tipo a través de comparaciones ordinarias (por ejemplo, ==/===), y siempre funciona?

Respuesta: No. No siempre TypeScript entiende el tipo a partir de comparaciones simples, especialmente si la comparación es demasiado "vaga" o se realiza a través de variables/properties indirectas. Para la reducción, a menudo es necesario utilizar mecánicas explícitas (typeof, instanceof, propiedades discriminantes y type guards).

Ejemplo:

function foo(x: number | string | null) { if (x) { // x: string | number, null ya no puede existir, pero no habrá reducción a uno concreto } }

Historia

En un gran proyecto de TypeScript, la condición user.role == 'admin' no redujo el tipo de datos, y aún así se necesitaban verificaciones para la existencia de la propiedad. Los desarrolladores subestimaron las reglas de reducción, lo que condujo a errores "Cannot read property ... of undefined".


Historia

En una aplicación móvil, la función aceptaba un objeto o una cadena. A través de una llamada indirecta a una función que cambiaba el tipo, no hubo reducción, y en algunos dispositivos ocurrió un fallo al llamar a un método que no existía en una cadena. Las pruebas fallaron en casos raros.


Historia

Al migrar el código de JavaScript a TypeScript, no implementaron sus funciones de type guard, asumiendo que las verificaciones de propiedades siempre reducirían el tipo. Como resultado, objetos complejos con campos opcionales se comportaron de manera incorrecta, y en tiempo de ejecución surgieron errores de acceso a datos impredecibles.