0Pricing
TypeScript Academy · Leçon

Le problème des HKT dans TypeScript

Comprendre pourquoi les constructeurs de types génériques sont difficiles à mettre en œuvre.

Le problème des HKT dans TypeScript est une leçon TypeScript Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage TypeScript Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours TypeScript Academy comprend 4 leçons au total.

Qu'est-ce qu'un type de niveau supérieur

Un type de niveau supérieur (HKT) abstrait non pas un type concret, mais un constructeur de type : quelque chose comme Array ou Promise, qui a besoin d'un argument pour devenir un type réel.

Array seul n'est pas un type. Array<string> en est un. Array est une fonction agissant sur les types, et les HKT permettent de rendre ces fonctions génériques.

type StringArray = Array<string>;
type NumberArray = Array<number>;
// Array by itself is a type constructor, not a type

Les genres, en bref

De même que les valeurs ont des types, les constructeurs de types ont des genres. Un type simple comme number est de genre *. Array est de genre * -> * : fournissez-lui un type et il renvoie un type. Rendre ces constructeurs génériques, c'est ce qu'on appelle « de niveau supérieur ».

type ValueLike = number;        // kind *
// Array needs one argument:    kind * -> *
// Map needs two arguments:     kind * -> * -> *

L'objectif : Functor<F>

Dans les langages qui prennent en charge les HKT, vous pouvez écrire une abstraction unique Functor<F> avec un seul map qui fonctionne pour n'importe quel conteneur F, qu'il s'agisse d'un tableau, d'une option ou d'une promesse. Une interface, de nombreux conteneurs.

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 it

Le problème

TypeScript ne prend pas en charge l'application d'un paramètre de type à un argument. Vous ne pouvez pas écrire F<A> lorsque F est un paramètre générique. Le compilateur renvoie l'erreur « Le type F n'est pas générique ».

// interface Functor<F> {
//   map<A, B>(fa: F<A>, f: (a: A) => B): F<B>;
// }
// Error: Type F is not generic

Pourquoi TS ne le prend pas en charge

Les paramètres de type de TypeScript sont du premier ordre : ils portent sur des types concrets, et non sur des constructeurs de types. Il n'existe aucune syntaxe pour dire que « F est quelque chose qui accepte un argument de type ». F<A> n'a donc aucun sens pour le compilateur.

// You can pass number, string, User as F...
// but not Array, not Promise (the constructors themselves)

Une difficulté concrète

Sans les HKT, vous devez dupliquer map pour chaque conteneur : une version pour les tableaux, une pour les options et une pour les promesses. La logique est identique, mais le système de types ne peut pas les unifier.

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 container

Ce que nous voulons exprimer

Nous voulons une seule signature : étant donné un conteneur de A et une fonction A -> B, renvoyer un conteneur de B, en préservant le type du conteneur. Un tableau reste un tableau ; une option reste une option.

// Wish: map<F, A, B>(fa: F<A>, f: (a: A) => B): F<B>
// where F is preserved across the call

Autres langages

Haskell et Scala prennent nativement en charge les HKT, ce qui permet d'y exprimer des classes de types comme Functor, Applicative et Monad. TypeScript a besoin d'une solution de contournement pour approcher les mêmes possibilités.

// Haskell: class Functor f where fmap :: (a -> b) -> f a -> f b
// TypeScript: needs an encoding trick (next lessons)

L'idée de l'encodage

La solution de contournement standard est la défonctionnalisation : au lieu d'appliquer directement F, nous attribuons à chaque conteneur une étiquette textuelle (un URI) et conservons un registre qui associe l'étiquette et un argument au type concret. L'application de type devient une recherche.

// Instead of F<A>, we write Kind<F, A> where F is a URI string
// and a registry resolves it to the real type

Ce que vous allez construire

Au cours des prochaines leçons, vous construirez progressivement l'encodage HKT de style fp-ts : un registre URItoKind, une recherche Kind, puis un Functor générique dont le map fonctionne pour tout conteneur enregistré.

// Roadmap:
// 1. Type constructors via URI strings
// 2. Kind<F, A> resolution
// 3. Generic Functor + instances

Pourquoi cela vaut la peine de le savoir

Vous écrirez rarement cet encodage vous-même, mais des bibliothèques comme fp-ts et Effect s'appuient dessus. Comprendre cette astuce vous permet de lire leurs types, d'écrire des abstractions génériques sur les conteneurs et de mieux comprendre ce que le système de types peut ou ne peut pas faire.

// Recognizing Kind<F, A> in library code is the payoff

Vérification rapide

Vérifiez votre compréhension du problème des HKT.

Récapitulatif

Vous avez découvert le problème des types de rang supérieur.

  • Les HKT permettent d'abstraire des constructeurs de types comme Array, et non des types concrets.
  • Les paramètres de TypeScript sont du premier ordre, donc F<A> est illégal.
  • Cela empêche de définir un unique Functor générique avec un seul map.
  • La solution consiste en un encodage utilisant des étiquettes URI et un registre.

Ensuite : définir des constructeurs de types au moyen de chaînes URI.

Questions Fréquemment Posées

La leçon « Le problème des HKT dans TypeScript » est-elle gratuite ?

Oui — le texte complet de « Le problème des HKT dans TypeScript » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours TypeScript Academy, passe à CoddyKit PRO. Le cours TypeScript Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Le problème des HKT dans TypeScript » ?

Comprendre pourquoi les constructeurs de types génériques sont difficiles à mettre en œuvre. Tu pratiques TypeScript Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer TypeScript Academy ?

Aucune expérience préalable n'est requise. TypeScript Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « Le problème des HKT dans TypeScript » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon TypeScript Academy ?

Oui. Chaque leçon TypeScript Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Le problème des HKT dans TypeScript
  2. Définir des constructeurs de types
  3. Le modèle HKT léger
  4. Foncteurs et mappeurs génériques
← Retour à TypeScript Academy