Il problema HKT in TypeScript
Comprenda perché i costruttori di tipi generici sono difficili da implementare.
Il problema HKT in TypeScript è una lezione TypeScript Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento TypeScript Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso TypeScript Academy include 4 lezioni in totale.
Che cos'è un tipo di ordine superiore
Un tipo di ordine superiore (HKT) non astrae su un tipo concreto, ma su un costruttore di tipi: qualcosa come Array o Promise che ha bisogno di un argomento per diventare un tipo reale.
Array da solo non è un tipo. Array<string> lo è. Array è una funzione sui tipi e gli HKT permettono di generalizzare su funzioni di questo tipo.
type StringArray = Array<string>;
type NumberArray = Array<number>;
// Array by itself is a type constructor, not a typeI kind in breve
Proprio come i valori hanno dei tipi, i costruttori di tipi hanno dei kind. Un tipo semplice come number ha kind *. Array ha kind * -> *: gli si fornisce un tipo e si ottiene un tipo in risposta. La generalizzazione su questi elementi è ciò che si definisce "higher-kinded".
type ValueLike = number; // kind *
// Array needs one argument: kind * -> *
// Map needs two arguments: kind * -> * -> *L'obiettivo: Functor<F>
Nei linguaggi che supportano gli HKT è possibile scrivere un'unica astrazione Functor<F> con un solo map che funziona per qualsiasi contenitore F, che sia un array, un option o una promise. Un'interfaccia, molti contenitori.
interface Wish_Functor<F> {
map<A, B>(fa: F<A>, f: (a: A) => B): F<B>;
}
// F<A> here is the wish - and TypeScript rejects itIl problema
TypeScript non supporta l'applicazione di un parametro di tipo a un argomento. Non è possibile scrivere F<A> quando F è un parametro generico. Il compilatore restituisce l'errore "Type F is not generic".
// interface Functor<F> {
// map<A, B>(fa: F<A>, f: (a: A) => B): F<B>;
// }
// Error: Type F is not genericPerché a TS manca questa funzionalità
I parametri di tipo di TypeScript sono di primo ordine: rappresentano tipi concreti, non costruttori di tipi. Non esiste una sintassi per dire "F è qualcosa che accetta un argomento di tipo". Pertanto F<A> non ha significato per il compilatore.
// You can pass number, string, User as F...
// but not Array, not Promise (the constructors themselves)Un problema concreto
Senza gli HKT è necessario duplicare map per ogni contenitore: uno per gli array, uno per le option e uno per le promise. La logica è identica, ma il sistema dei tipi non è in grado di unificarli.
declare function mapArray<A, B>(fa: A[], f: (a: A) => B): B[];
declare function mapOption<A, B>(fa: A | null, f: (a: A) => B): B | null;
// Same shape, but no way to abstract over the containerCiò che vogliamo esprimere
Vogliamo un'unica firma: dato un contenitore di A e una funzione A -> B, restituire un contenitore di B, preservando il tipo di contenitore. Array resta Array; Option resta Option.
// Wish: map<F, A, B>(fa: F<A>, f: (a: A) => B): F<B>
// where F is preserved across the callAltri linguaggi
Haskell e Scala supportano nativamente gli HKT, ed è per questo che in questi linguaggi è possibile esprimere type class come Functor, Applicative e Monad. TypeScript ha bisogno di una soluzione alternativa per approssimare la stessa potenza.
// Haskell: class Functor f where fmap :: (a -> b) -> f a -> f b
// TypeScript: needs an encoding trick (next lessons)L'idea alla base della codifica
La soluzione alternativa standard è la defunzionalizzazione: invece di applicare direttamente F, assegniamo a ogni contenitore un tag stringa (un URI) e manteniamo un registro che associa il tag più un argomento al tipo concreto. L'applicazione di tipo diventa una ricerca.
// Instead of F<A>, we write Kind<F, A> where F is a URI string
// and a registry resolves it to the real typeCosa costruirà
Nelle prossime lezioni costruirà passo dopo passo la codifica HKT nello stile di fp-ts: un registro URItoKind, una ricerca tramite Kind e infine un Functor generico il cui map funziona con qualsiasi contenitore registrato.
// Roadmap:
// 1. Type constructors via URI strings
// 2. Kind<F, A> resolution
// 3. Generic Functor + instancesPerché vale la pena conoscerlo
Raramente si scrive personalmente questa codifica, ma librerie come fp-ts ed Effect si basano su di essa. Comprendere questo meccanismo permette di leggere i loro tipi, scrivere astrazioni generiche sui contenitori e capire meglio cosa il sistema dei tipi può e non può fare.
// Recognizing Kind<F, A> in library code is the payoffVerifica rapida
Verifichi la sua comprensione del problema degli HKT.
Riepilogo
Ha incontrato il problema dei tipi di tipo superiore.
- Gli HKT astraggono sui costruttori di tipi come
Array, non sui tipi concreti. - I parametri di TypeScript sono di primo ordine, quindi
F<A>non è consentito. - Questo impedisce di creare un unico
Functorgenerico con un solomap. - La soluzione è una codifica che usa tag URI e un registro.
Prossimo argomento: definire i costruttori di tipi tramite stringhe URI.
Domande Frequenti
La lezione «Il problema HKT in TypeScript» è gratuita?
Sì — il testo completo di «Il problema HKT in TypeScript» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso TypeScript Academy, passa a CoddyKit PRO. Il corso TypeScript Academy include 4 lezioni in totale.
Cosa imparerò in «Il problema HKT in TypeScript»?
Comprenda perché i costruttori di tipi generici sono difficili da implementare. Eserciti TypeScript Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare TypeScript Academy?
Non è richiesta alcuna esperienza precedente. TypeScript Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Il problema HKT in TypeScript»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione TypeScript Academy?
Sì. Ogni lezione TypeScript Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Il problema HKT in TypeScript
- Definire costruttori di tipi
- Il pattern HKT leggero
- Functor e mapper generici