0Pricing
TypeScript Academy · Lektion

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 application

Der 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 | null

F 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 URI

Generische 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 table

Einschrä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 ceremony

Alles 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 Kind statt F<A>.
  • Das Muster lässt sich mit Kind2 auf 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

  1. Das HKT-Problem in TypeScript
  2. Typkonstruktoren definieren
  3. Das schlanke HKT-Muster
  4. Generische Funktoren und Mapper
← Zurück zu TypeScript Academy