Saltar al contenido
#237 unique-tuple · par 4

    ↑↓ mover · ⏎ abrir · esc cerrar

    N.º 237 · 20 de agosto de 2026 · Difícil

    Únicos

    Implementa `Unique<T>` para que elimine elementos duplicados de una tupla, conservando la primera aparición de cada uno. `Includes` del puzle n.º 227 está disponible.

    01

    Intenta el puzle tú mismo

    Par 4

    Puzle

    unique-tuple.ts
    type Includes<T extends readonly unknown[], U> =
      T extends readonly [infer H, ...infer R]
        ? Equal<H, U> extends true
          ? true
          : Includes<R, U>
        : false
    Intento 1 de 4Aún sin comprobar

    Sustituye ??? — tu solución se comprueba con los casos de abajo. Tab indenta; pulsa Escape y luego Tab para sacar el foco.

    Comprobaciones

    4
    • Unique<[1, 2, 2, 3, 1]>
      [1, 2, 3]
    • Unique<[]>
      []
    • Unique<['a', 'b']>
      ['a', 'b']
    • Unique<[1, 1, 1]>
      [1]

    Cómo se juzga una comprobación Igualdad exacta de tipos, no asignabilidad — una intersección no es lo mismo que el objeto aplanado.

    Cómo le fue a todo el mundo

    Menos de 5 personas han resuelto este puzle hasta ahora. La distribución aparece cuando la muestra sea lo bastante grande como para significar algo.

    Juego corto

    Menos caracteres

    Aún no hay marcas públicas.

    Archivo
    02

    Solución comentada

    Publicado el 21 de agosto de 2026

    La solución

    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

    El error más común

    type Unique<T extends readonly unknown[]> =
      T extends readonly [infer H, ...infer R]
        ? Includes<R, H> extends true
          ? Unique<R>
          : [H, ...Unique<R>]
        : []

    Esto mira hacia delante en vez de recordar. Cuando un elemento reaparece más tarde, descarta la *primera* aparición y conserva la última, así que `[1, 2, 2, 3, 1]` queda como `[2, 3, 1]`. Los elementos son correctos, el orden no.

    Línea por línea

    1. Acc extends unknown[] = []

      Un parámetro de tipo con valor por defecto es cómo una función a nivel de tipos lleva estado. Quien la llama nunca lo pasa; cada llamada recursiva encadena el resultado que va creciendo.

    2. Includes<Acc, H>

      La prueba de pertenencia se hace contra lo ya conservado, no contra lo que queda por venir. Esa es la diferencia entre conservar la primera aparición y conservar la última.

    3. : Acc

      Cuando la entrada se agota, el acumulador *es* la respuesta, así que se devuelve directamente en vez de construirlo al salir. Es una forma de recursión de cola, y TypeScript la maneja con menos pila que la forma cabeza-cola.

    Para recordar

    Un parámetro acumulador convierte una recursión que construye hacia atrás en una que construye hacia delante. Cuesta un parámetro de tipo y aporta orden correcto y un límite de recursión más profundo.

    Usa