Concepto 7 de 12
infer
`infer` es emparejamiento de patrones. Describes la forma que esperas, pones `infer X` donde está la parte interesante, y el compilador resuelve `X`. Casi todos los helpers de extracción de la librería estándar son un condicional con un `infer` bien colocado.
Funciona en cualquier sitio donde quepa un tipo
type Unwrap<T> = T extends Promise<infer Inner> ? Inner : T type Element<T> = T extends (infer E)[] ? E : never type Returns<T> = T extends (...a: never[]) => infer R ? R : never type Head<T> = T extends [infer H, ...unknown[]] ? H : never type Rest<S> = S extends `${string}-${infer R}` ? R : never
Promesas, arrays, retornos de función, posiciones de tupla, patrones de cadena — el mecanismo es idéntico cada vez. Solo cambia la forma que lo rodea, y por eso aprender uno te enseña todos.
Restringir lo que se liga
// Without the constraint, F is unknown and cannot be // interpolated into a template literal. type First<T> = T extends [infer F extends string, ...unknown[]] ? `${F}!` : never
Un `infer` puede llevar su propia cláusula `extends`, que acota lo que liga y permite usar el resultado donde se exige un tipo concreto. Sin ella sueles obtener `unknown`, y el error aparece una línea después de la causa.
El error más común
// Intent: get the return type of any function. type Returns<T> = T extends () => infer R ? R : never Returns<() => string> // string Returns<(a: number) => string> // never — pattern demands zero parameters // Fixed: never[] in parameter position accepts any signature, // because parameters are checked contravariantly. type Returns2<T> = T extends (...a: never[]) => infer R ? R : never
El patrón debe ser tan permisivo como las entradas que quieras emparejar. Un tipo de función sin parámetros solo encaja con funciones sin parámetros, así que todo lo demás cae en silencio en la rama falsa.
Para recordar
Describe la forma, marca el hueco con `infer` y deja que el compilador lo rellene. Si nada encaja, el patrón es más estricto que la entrada — no al revés.