Saltar al contenido
webtype.orgDoce conceptos · 10/12

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.

Se practica en