La nouvelle syntaxe de paramètre de type const de TypeScript permet à une fonction de conserver les types littéraux intacts sans forcer les appelants à parsemer partout des as const, éliminant ainsi la source la plus courante de bugs d'élargissement de type (type-widening).

Le problème d'élargissement qui hante le code générique

Lorsqu'une fonction générique reçoit un objet littéral, le compilateur élargit toute propriété littérale vers son type primitif plus large.

function call<T>(arg: T) {}
call({ method: "GET" })   // T is inferred as { method: string }

Le littéral "GET" se réduit à string. Le code en aval qui dépend de la valeur exacte — comme les unions discriminées ou l'extraction par template-literal — se brise car le type ne porte plus le littéral précis. Les développeurs contournent cela depuis longtemps en écrivant { method: "GET" } as const au moment de l'appel, ce qui indique au compilateur de conserver le littéral, mais cette correction repose entre les mains de l'appelant et non dans la définition de la fonction.

Paramètres de type const : une correction au niveau de la signature

Le nouveau modificateur const sur un paramètre de type indique au compilateur d'inférer le type le plus étroit possible pour cet argument générique. Déclarer une fonction comme function foo<const T>(arg: T) fait que T se comporte automatiquement comme si l'appelant avait écrit as const.

  • Les littéraux de type string, number, boolean conservent leurs valeurs exactes ("GET" au lieu de string).
  • Les tableaux deviennent des tuples en lecture seule (readonly) où chaque élément est typé précisément.
  • Les objets se transforment en structures profondément en lecture seule, préservant les types littéraux à chaque niveau d'imbrication.

Comme la contrainte réside dans la signature de la fonction, chaque appelant en bénéficie automatiquement ; oublier un cast n'est plus une source d'insécurité (unsoundness).

Pourquoi cela surpasse l'astuce classique as const

as const est une solution du côté de l'appelant. Elle exige que chaque consommateur d'une fonction générique se souvienne d'ajouter l'assertion. Un seul appel oublié, et la sécurité de type s'évapore. Le paramètre de type const déplace la responsabilité au sein même de la conception de l'API : la fonction déclare « j'ai besoin de la forme la plus étroite de ce que vous passez », et le compilateur l'applique.

Ce changement est crucial pour les bibliothèques et les utilitaires qui exposent des constructeurs génériques, des usines de configuration (factories), ou toute API où la valeur littérale d'un champ pilote la logique de type. L'auteur de la bibliothèque peut garantir une inférence correcte sans avoir à surveiller le code en aval.

Scénarios concrets qui en profitent

  • Constructeurs de configuration – les noms d'environnement ("dev" | "prod") restent littéraux, permettant des vérifications d'unions discriminées sans casts supplémentaires.
  • Définitions de routes d'API – les chaînes de chemin restent exactes, permettant aux types template-literal d'extraire des paramètres ("/users/:id"\/users/${string}``).
  • Aides aux machines à états – les identifiants d'état restent des littéraux fixes via le chaînage de méthodes, évitant les incohérences d'état accidentelles.

Dans chaque cas, le paramètre const élimine la répétition de code (boilerplate) as const et réduit le risque de laisser passer des bugs subtils.

Couplage avec l'opérateur satisfies

L'opérateur satisfies valide qu'une valeur est conforme à un type structurel tout en préservant ses informations littérales d'origine. L'utilisation des deux ensemble offre le meilleur des deux mondes : les paramètres const fournissent une inférence étroite, et satisfies garantit que la valeur respecte la forme requise.

function makeConfig<const C>(cfg: C) {
  // cfg is inferred with exact literals
}
const cfg = {
  env: "staging",
  ports: [8080, 8443],
} satisfies { env: string; ports: number[] };
makeConfig(cfg); // works, literals stay intact

Quand conserver as const

Le paramètre const est particulièrement efficace lorsque vous contrôlez la signature de la fonction. Si vous utilisez des fonctions tierces qui ne possèdent pas ce modificateur, ou si vous avez besoin d'une préservation littérale ponctuelle pour une variable locale, as const reste l'outil approprié. Il demeure la méthode de référence pour figer une valeur sans modifier l'API appelée.

À surveiller ensuite

Cette fonctionnalité est récente, les outils et les modèles de la communauté sont donc en pleine évolution. Attendez-vous à des mises à jour du support des IDE qui feront apparaître la nouvelle syntaxe dans l'autocomplétion et les suggestions de correction rapide. Gardez un œil sur les mainteneurs de bibliothèques : beaucoup commenceront à migrer leurs génériques publics vers des paramètres const, ce qui pourrait introduire des changements de rupture (breaking changes) pour le code qui reposait auparavant sur des casts as const explicites.

À retenir : En intégrant la préservation des littéraux directement dans les paramètres de type d'une fonction, les paramètres de type const de TypeScript éliminent une source courante d'erreurs d'élargissement et transfèrent la responsabilité de la sécurité de l'appelant vers le concepteur de l'API. Utilisez-les pour tous les points d'entrée génériques que vous contrôlez ; réservez as const pour les valeurs locales ou les API externes.