El patrón HKT ligero
Implemente el truco de defuncionalización Kind/URI.
El patrón HKT ligero es una lección gratuita de TypeScript Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de TypeScript Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de TypeScript Academy incluye 4 lecciones en total.
Defuncionalización
El truco detrás de la codificación tiene un nombre: defuncionalización. En lugar de una función de tipos real de orden superior, representamos cada función mediante una etiqueta y la resolvemos con una única búsqueda de primer orden. El registro URItoKind es esa tabla de búsqueda.
type Kind<F extends URIS, A> = URItoKind<A>[F];
// One lookup replaces true type-function applicationEl tipo Kind
Kind<F, A> es la parte pública del patrón. Se lee como «el constructor F aplicado a A». Oculta la indexación del registro tras un nombre claro.
type A = Kind<"Array", number>; // number[]
type B = Kind<"Option", string>; // string | nullRestringir F a URIS
F debe ser una URI registrada. Restringimos F con extends URIS para que solo puedan utilizarse etiquetas válidas y los errores tipográficos se conviertan en errores de compilación.
type Kind<F extends URIS, A> = URItoKind<A>[F];
// Kind<"Arrey", number> -> error, not a valid URIEscribir firmas genéricas
Ahora podemos escribir la firma de Functor que antes era imposible. Sustituya cada F<A> por Kind<F, A> y el compilador la aceptará.
interface Functor<F extends URIS> {
map<A, B>(fa: Kind<F, A>, f: (a: A) => B): Kind<F, B>;
}La resolución en acción
Cuando fija F a una URI concreta, Kind se resuelve en el tipo de contenedor real. Un Functor<"Array"> tiene un map de A[] a B[].
type ArrayFunctor = Functor<"Array">;
// map: <A, B>(fa: A[], f: (a: A) => B) => B[]Varios argumentos de tipo
Algunos constructores reciben dos argumentos, como Either<E, A>. fp-ts amplía el patrón con URItoKind2 y Kind2<F, E, A> para el kind * -> * -> *. La idea se amplía añadiendo más registros.
interface URItoKind2<E, A> {
Either: { left: E } | { right: A };
}
type Kind2<F extends URIS2, E, A> = URItoKind2<E, A>[F];La convención de fp-ts
fp-ts estableció la convención que sigue todo este curso: una cadena URI por tipo de datos, un registro URItoKind ampliado mediante la fusión de declaraciones y Kind para la resolución. Reconocerla le permite leer las firmas de tipos de fp-ts y Effect.
// In fp-ts you will see exactly:
// declare module "fp-ts/HKT" { interface URItoKind<A> { ... } }Un registro de instancia
Una «instancia» de una abstracción es un valor que la implementa para una URI específica. La instancia incluye el map concreto. En la próxima lección escribiremos la instancia de Array; aquí se muestra su estructura.
declare const arrayFunctor: Functor<"Array">;
const out = arrayFunctor.map([1, 2, 3], n => n * 2); // number[]Por qué es «ligero»
Se denomina patrón de HKT ligero porque no necesita cambios en el compilador ni sintaxis especial, solo interfaces y acceso indexado. El coste es añadir un poco de ceremonia (URI y registros) a cambio de obtener código realmente genérico para contenedores.
type Kind<F extends URIS, A> = URItoKind<A>[F];
// No magic, just a typed lookup tableLimitaciones
El patrón es verboso y los mensajes de error pueden resultar crípticos porque mencionan la codificación en lugar de su dominio. Además, requiere registrar cada contenedor. En la mayoría de las aplicaciones, se consumen bibliotecas que ya hacen esto en lugar de construirlo por cuenta propia.
// Trade-off: real abstraction power vs. encoding ceremonyUnir todas las piezas
La receta completa del HKT ligero es: definir una URI, registrarla en URItoKind, definir abstracciones mediante Kind<F, A> y proporcionar instancias para cada URI. Ese es todo el conjunto de herramientas en el que se basan las bibliotecas funcionales genéricas de TypeScript.
type Kind<F extends URIS, A> = URItoKind<A>[F];
interface Functor<F extends URIS> {
map<A, B>(fa: Kind<F, A>, f: (a: A) => B): Kind<F, B>;
}Comprobación rápida
Compruebe su comprensión del patrón HKT ligero.
Repaso
Ha ensamblado el patrón HKT ligero.
- La defuncionalización sustituye la aplicación de funciones de tipos por una búsqueda.
Kind<F, A>resuelve una URI más un argumento en un tipo concreto.- Las firmas genéricas utilizan
Kinden lugar deF<A>. - Se amplía a dos argumentos mediante
Kind2y constituye la convención de fp-ts.
A continuación: un map genérico con instancias reales.
Preguntas frecuentes
¿La lección «El patrón HKT ligero» es gratis?
Sí — el texto completo de «El patrón HKT ligero» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de TypeScript Academy, actualiza a CoddyKit PRO. El curso de TypeScript Academy incluye 4 lecciones en total.
¿Qué aprenderé en «El patrón HKT ligero»?
Implemente el truco de defuncionalización Kind/URI. Practicas TypeScript Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar TypeScript Academy?
No se requiere experiencia previa. TypeScript Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «El patrón HKT ligero»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de TypeScript Academy?
Sí. Cada lección de TypeScript Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- El problema de HKT en TypeScript
- Definición de constructores de tipos
- El patrón HKT ligero
- Functors y mappers genéricos