Das schlanke HKT-Muster
Implementieren Sie den Defunktionalisierungstrick mit Kind/URI.
Das schlanke HKT-Muster ist eine kostenlose TypeScript Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des TypeScript Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der TypeScript Academy-Kurs umfasst insgesamt 4 Lektionen.
Defunktionalisierung
Der Trick hinter der Kodierung hat einen Namen: Defunktionalisierung. Statt einer echten höhergeordneten Typfunktion repräsentieren wir jede Funktion durch ein Tag und lösen sie mit einem einzigen erststufigen Lookup auf. Die URItoKind-Registry ist diese Lookup-Tabelle.
type Kind<F extends URIS, A> = URItoKind<A>[F];
// One lookup replaces true type-function applicationDer Typ Kind
Kind<F, A> ist die öffentliche Schnittstelle dieses Musters. Lesen Sie es als „der Konstruktor F, angewendet auf A“. Es verbirgt die Indizierung der Registry hinter einem klaren Namen.
type A = Kind<"Array", number>; // number[]
type B = Kind<"Option", string>; // string | nullF auf URIS beschränken
F muss eine registrierte URI sein. Beschränken Sie es mit extends URIS, damit nur gültige Tags verwendet werden können und Tippfehler zu Kompilierungsfehlern führen.
type Kind<F extends URIS, A> = URItoKind<A>[F];
// Kind<"Arrey", number> -> error, not a valid URIGenerische Signaturen schreiben
Jetzt können wir die zuvor unmögliche Functor-Signatur schreiben. Ersetzen Sie jedes F<A> durch Kind<F, A>, und der Compiler akzeptiert sie.
interface Functor<F extends URIS> {
map<A, B>(fa: Kind<F, A>, f: (a: A) => B): Kind<F, B>;
}Auflösung in Aktion
Wenn Sie F auf eine konkrete URI festlegen, wird Kind in den tatsächlichen Containertyp aufgelöst. Ein Functor<"Array"> verfügt über ein map von A[] nach B[].
type ArrayFunctor = Functor<"Array">;
// map: <A, B>(fa: A[], f: (a: A) => B) => B[]Mehrere Typargumente
Einige Konstruktoren akzeptieren zwei Argumente, etwa Either<E, A>. fp-ts erweitert das Muster mit URItoKind2 und Kind2<F, E, A> für den Kind * -> * -> *. Das Prinzip lässt sich durch zusätzliche Registries erweitern.
interface URItoKind2<E, A> {
Either: { left: E } | { right: A };
}
type Kind2<F extends URIS2, E, A> = URItoKind2<E, A>[F];Die Konvention von fp-ts
fp-ts hat die Konvention etabliert, der dieser gesamte Kurs folgt: ein URI-String pro Datentyp, eine durch Declaration Merging erweiterte URItoKind-Registry und Kind zur Auflösung. Wenn Sie diese Konvention erkennen, können Sie die Typsignaturen von fp-ts und Effect lesen.
// In fp-ts you will see exactly:
// declare module "fp-ts/HKT" { interface URItoKind<A> { ... } }Ein Instanz-Record
Eine „Instanz“ einer Abstraktion ist ein Wert, der diese für eine bestimmte URI implementiert. Die Instanz enthält das konkrete map. In der nächsten Lektion schreiben wir die Array-Instanz; hier sehen Sie ihre Form.
declare const arrayFunctor: Functor<"Array">;
const out = arrayFunctor.map([1, 2, 3], n => n * 2); // number[]Warum dieses Muster „leichtgewichtig“ ist
Es wird als leichtgewichtiges HKT-Muster bezeichnet, weil es keine Compileränderungen und keine spezielle Syntax benötigt, sondern nur Schnittstellen und indizierte Zugriffe. Der Preis ist etwas zusätzlicher Schreibaufwand (URIs, Registries) für tatsächlich containergenerischen Code.
type Kind<F extends URIS, A> = URItoKind<A>[F];
// No magic, just a typed lookup tableEinschränkungen
Das Muster ist ausführlich, und Fehlermeldungen können kryptisch sein, weil sie statt Ihrer Domäne die Kodierung erwähnen. Außerdem muss jeder Container registriert werden. In den meisten Anwendungen verwenden Sie Bibliotheken, die dies bereits erledigen, statt es selbst zu implementieren.
// Trade-off: real abstraction power vs. encoding ceremonyAlles zusammenfügen
Das vollständige Rezept für leichtgewichtige HKTs: Definieren Sie eine URI, registrieren Sie sie in URItoKind, definieren Sie Abstraktionen mit Kind<F, A> und stellen Sie Instanzen pro URI bereit. Das ist das gesamte Werkzeug hinter generischen funktionalen Bibliotheken in 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>;
}Kurzer Test
Testen Sie Ihr Verständnis des leichtgewichtigen HKT-Musters.
Zusammenfassung
Sie haben das leichtgewichtige HKT-Muster zusammengesetzt.
- Defunktionalisierung ersetzt die Anwendung von Typfunktionen durch einen Lookup.
Kind<F, A>löst eine URI zusammen mit einem Argument in einen konkreten Typ auf.- Generische Signaturen verwenden
KindstattF<A>. - Das Muster lässt sich mit
Kind2auf zwei Argumente erweitern und entspricht der Konvention von fp-ts.
Als Nächstes: ein generisches map mit echten Instanzen.
Häufig gestellte Fragen
Ist die Lektion „Das schlanke HKT-Muster“ kostenlos?
Ja — der vollständige Text von „Das schlanke HKT-Muster“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des TypeScript Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der TypeScript Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Das schlanke HKT-Muster“?
Implementieren Sie den Defunktionalisierungstrick mit Kind/URI. Du übst TypeScript Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um TypeScript Academy zu starten?
Keine Vorkenntnisse erforderlich. TypeScript Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Das schlanke HKT-Muster“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser TypeScript Academy-Lektion Code schreiben und ausführen?
Ja. Jede TypeScript Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Das HKT-Problem in TypeScript
- Typkonstruktoren definieren
- Das schlanke HKT-Muster
- Generische Funktoren und Mapper