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:
Ejemplo:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
¿Se pueden usar múltiples infer en un solo tipo condicional? ¿Cómo interpreta TypeScript este caso?
Respuesta incorrecta:
Respuesta correcta:
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;
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.