Concepto 10 de 12
Recursión
No hay bucles a nivel de tipos, así que la recursión es la única forma de procesar algo de longitud desconocida. La forma es siempre la misma: separa una pieza, trátala, recurre sobre el resto y para cuando no quede nada.
Cabeza y cola
type Reverse<T extends readonly unknown[]> = T extends readonly [infer H, ...infer R] ? [...Reverse<R>, H] : [] // The order you REBUILD in is the whole difference: // [H, ...Reverse<R>] copies // [...Reverse<R>, H] reverses
La rama falsa es la salida y debe devolver el elemento neutro de lo que construyes: `[]` para tuplas, `''` para cadenas, `{}` para objetos. Devuelve ahí el contenido y tendrás un desfase de uno que solo se ve al final.
Los acumuladores construyen hacia delante
type Unique<T extends readonly unknown[], Acc extends unknown[] = []> = T extends readonly [infer H, ...infer R] ? Includes<Acc, H> extends true ? Unique<R, Acc> : Unique<R, [...Acc, H]> : Acc
Un parámetro con valor por defecto lleva estado que quien llama nunca pasa. Más allá de la corrección — es lo que permite a `Unique` conservar la *primera* aparición y no la última — la forma de recursión de cola también gasta menos pila del compilador que construir el resultado al salir.
Hay un límite de profundidad
// Around 1000 levels, then: // "Type instantiation is excessively deep and possibly infinite."
TypeScript se detiene sobre las mil instanciaciones. La recursión de cola sube bastante el techo, pero el límite es real y por eso nadie publica una calculadora a nivel de tipos que maneje números grandes.
El error más común
// Intent: flatten completely, to any depth. type Flatten<T extends readonly unknown[]> = T extends readonly [infer H, ...infer R] ? H extends readonly unknown[] ? [...H, ...Flatten<R>] // <- only unwraps ONE layer : [H, ...Flatten<R>] : [] Flatten<[[[1]]]> // [[1]] — stopped one level early
Expandir `H` abre una capa; recurrir dentro de ella las abre todas. Recurrir en una dirección recorre una lista, en dos recorre un árbol — y «solo bajó un nivel» es casi siempre una segunda llamada recursiva que falta.
Para recordar
Divide, trata, recurre, para. El caso base devuelve el elemento neutro, y la dirección en que reensamblas es lo que distingue una copia de una inversión, un filtro o un map.