Los tipos distributivos (Distributive Types) son una característica de TypeScript que se manifiesta al trabajar con tipos condicionales (T extends U ? X : Y). Cuando una variable-tipo a la izquierda de extends es una unión (union), TypeScript distribuye la condición sobre cada elemento de la unión.
Ejemplo:
// "Test<A> | Test<B> | Test<C>" type Test<T> = T extends string ? () => string : () => number; type Result = Test<'A' | 'B' | 'C'>;
Aquí Result se distribuirá como:
Cuándo se aplican — para escribir API universales, manipulaciones sobre uniones, por ejemplo, para filtrado o coincidencia de patrones.
Características:
[T], no se producirá la distribución. Esta es una forma de "desactivar" la distribución.Pregunta: ¿El tipo T[] extends number[] ? true : false será distributivo?
Respuesta correcta: No, la distribución ocurre solo si a la izquierda hay una variable-tipo sin envoltura en un array o tupla. Por ejemplo, el tipo condicional T extends number ? ... distribuirá, pero T[] extends number[] ? ... — no.
Historia
Proyecto: Biblioteca de validación de props para componentes de React. Querían implementar un tipo que convertía los props de tipo unión en una interfaz estricta, pero debido a un desconocimiento de la distribución, el tipo se volvió inesperadamente complejo (las propiedades de los miembros de la unión se mezclaron). Lo corrigieron añadiendo una envoltura
[T]para que no ocurriera la distribución.
Historia
Proyecto: Desarrollaron el manejo de todos los tipos de eventos en una única función manejadora. En el tipo condicional se esperaba que la función aceptara cada tipo de evento mediante la distribución, pero al no usarla explícitamente, implementaron el manejo incorrectamente, lo que condujo a tipos erróneos de argumentos (unión en lugar de una llamada separada para cada tipo).
Historia
Proyecto: Al crear sus propios tipos utilitarios (tipo Exclude, Extract) olvidaron que la distribución no ocurriría para tuplas y arrays. Como resultado, el tipo Exclude no funcionó para arrays (por ejemplo, el tipo
Exclude<["a"|"b"], "b">no eliminaba "b").