ProgramaciónDesarrollador TypeScript/Fullstack

¿Cómo funcionan los Conditional Types con infer en TypeScript, en qué situaciones son necesarios y qué errores se encuentran en la práctica?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Los Conditional Types utilizando la palabra clave infer permiten extraer tipos de tipos de datos complejos. Un ejemplo clásico es la extracción del tipo de un elemento de un arreglo:

type ElementType<T> = T extends (infer U)[] ? U : T;

Aquí infer U permite calcular el tipo del elemento del arreglo T. Si T es un arreglo, se devolverá el tipo de sus elementos; de lo contrario, se devolverá T mismo.

Dónde se utilizan:

  • Para escribir tipos helper genéricos (por ejemplo, extracción del tipo de retorno de una función, tipo de valor de Promise, etc.).

Ejemplo:

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

Pregunta trampa.

¿Se pueden usar múltiples infer en un solo tipo condicional? ¿Cómo interpreta TypeScript este caso?

Respuesta incorrecta:

  • "No se puede usar más de un infer, TypeScript no lo permitirá."

Respuesta correcta:

  • Se pueden utilizar múltiples variables infer en un solo patrón. Por ejemplo, al descomponer una tupla:
type FirstArgument<T> = T extends (infer F, ...any[]) => any ? F : never; // Pero es más correcto con funciones: type Args<T> = T extends (...args: infer A) => any ? A : never;
  • TypeScript correctamente deduce múltiples tipos a través de diferentes variables infer.

Ejemplos de errores reales por desconocimiento de las sutilezas del tema.


Historia

Un desarrollador escribió un modo para obtener el tipo de un objeto devuelto por una función, pero no consideró que la función podría devolver un Promise. Como resultado, el tipo del valor devuelto siempre fue Promise<any>, ya que no se usó un conditional embedding con extract/infer. Tuvo que refactorizar el código en toda la base.


Historia

En el proyecto se introdujo un tipo genérico para desempaquetar arreglos anidados, pero se olvidó de especificar la rama else final en la condición. TypeScript no presentó un error correctamente, pero al usarlo en algunos casos el resultado fue never, lo que rompió algunas utilidades de tipificación en bibliotecas externas.


Historia

Un colega intentó extraer los tipos de las propiedades de una gran interfaz a través de un tipo combinado condicional/infer, sin considerar que algunas propiedades eran tipos de unión. Como resultado, hubo combinaciones inesperadas de tipos de unión en la salida, el compilador lo pasó por alto y la lógica funcionó incorrectamente.