Menu

Template literal types en TypeScript : syntaxe et exemples

Les template literal types construisent des types littéraux de chaîne avec la même syntaxe à backticks que les template strings JavaScript : on${Capitalize<E>}. Découvrez la syntaxe, la multiplication des unions, Uppercase et Capitalize, les motifs comme ${number}px, les getters générés par mapped types et l'analyse de chaînes avec infer.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Un template literal type construit des types littéraux de chaîne avec la même syntaxe à backticks qu'une template string JavaScript. `on${Capitalize<"click" | "focus">}` est le type "onClick" | "onFocus", calculé par le compilateur :

Les template literal types n'existent qu'à la compilation. Ils vérifient les littéraux de chaîne et les valeurs typées pendant que vous écrivez le code ; ils n'ajoutent rien au JavaScript produit. La table de handlers ci-dessus utilise Record pour exiger une fonction par nom.

Syntaxe

Entre les backticks, on écrit du texte littéral et des emplacements ${...}. Un emplacement contient un type, pas une valeur : un type littéral string, number, bigint ou boolean, une union de ces types, ou l'un des types larges string, number, bigint, boolean, null et undefined.

Un emplacement avec un type large comme string ou number crée un motif : le type reste `hello ${string}` et toute chaîne qui correspond est acceptée. Un emplacement avec une union finie, comme boolean, est développé en ses membres.

Les unions se multiplient

Avec plusieurs unions, le résultat contient toutes les combinaisons :

Trois tailles fois deux tons donnent six membres. Le nombre grimpe vite : cinq emplacements contenant chacun une union de dix lettres donneraient 100 000 membres, et TypeScript refuse avec error TS2590: Expression produces a union type that is too complex to represent. Utilisez un emplacement large comme ${string} quand vous n'avez pas besoin de chaque valeur exacte.

Uppercase, Lowercase, Capitalize, Uncapitalize

Quatre types intégrés changent la casse des types littéraux de chaîne. Ils sont intrinsèques : implémentés dans le compilateur, et non écrits en TypeScript.

TypeEntréeRésultat
Uppercase<S>"hello world""HELLO WORLD"
Lowercase<S>"Content-Type""content-type"
Capitalize<S>"hello world""Hello world"
Uncapitalize<S>"UserName""userName"

Ils ne changent que les types. Pour construire la chaîne correspondante à l'exécution, il faut toujours appeler toUpperCase() ou découper et mettre en majuscule vous-même, puis indiquer à TypeScript que le résultat a le type précis :

Le as est nécessaire parce que toUpperCase() est typé pour renvoyer un simple string. C'est la signature de la fonction que voient les appelants, donc capitalize("report") a le type littéral "Report".

Motifs de chaîne : ${number}px et compagnie

Un type motif accepte toute chaîne d'une forme donnée. C'est pratique pour les valeurs CSS, les identifiants et les clés avec un préfixe connu :

${number} accepte toute chaîne que JavaScript lit comme un nombre, ce qui est plus permissif qu'il n'y paraît : "-3px", "1e3px" et "0x10px" passent tous la vérification. Voyez ces motifs comme une protection contre les fautes de frappe dans les littéraux, pas comme une validation complète.

Template literals et mapped types

Les template literal types sont surtout utiles dans la clause as d'un mapped type, où ils génèrent des noms de propriétés à partir d'autres noms de propriétés :

string & K ne garde que les clés de type chaîne, car Capitalize n'accepte ni nombres ni symboles. Chaque callback reçoit le type de son paramètre depuis la propriété qu'il surveille.

Analyser des chaînes avec infer

Dans un type conditionnel, un template literal peut reconnaître une chaîne et en capturer des parties avec infer. Cet exemple extrait les noms de paramètres d'un motif de route :

Oubliez postId dans l'appel et le compilateur le signale comme manquant.

Les expressions template s'élargissent en string

Une expression template string dans du code ordinaire est typée string, même quand chaque partie est un type littéral. Ajoutez as const pour conserver le template literal type :

Sans as const, affecter loose à `log:${Level}` échoue, car string pourrait être n'importe quoi.

Questions fréquentes

Que sont les template literal types en TypeScript ?

Des types littéraux de chaîne écrits avec des backticks et des emplacements ${...}, comme les template strings JavaScript mais au niveau des types. type Greeting = `hello ${string}` accepte toute chaîne qui commence par hello , et `on${Capitalize<"click">}` est le type littéral "onClick".

Que se passe-t-il quand on met une union dans un template literal type ?

Le template est développé pour chaque membre, et avec plusieurs unions on obtient toutes les combinaisons. `${"sm" | "lg"}-${"red" | "blue"}` vaut "sm-red" | "sm-blue" | "lg-red" | "lg-blue". Les combinaisons trop grandes échouent avec l'erreur TS2590.

À quoi servent Uppercase, Lowercase, Capitalize et Uncapitalize ?

Ce sont des types intégrés qui transforment des types littéraux de chaîne : Uppercase<"id"> vaut "ID", Lowercase<"ID"> vaut "id", Capitalize<"name"> vaut "Name" et Uncapitalize<"Name"> vaut "name". Ils ne changent que les types ; pour modifier une chaîne à l'exécution, il faut toujours appeler toUpperCase() et consorts.

Les template literal types valident-ils les chaînes à l'exécution ?

Non. Comme tous les types TypeScript, ils sont effacés : ils ne vérifient les littéraux de chaîne et les valeurs typées qu'à la compilation. Une chaîne qui arrive à l'exécution, depuis du JSON ou une saisie utilisateur, reste un simple string tant que votre propre code ne l'a pas vérifiée.

Pourquoi ma template string est-elle typée string et non comme un type littéral ?

Une expression template comme `on${event}` est élargie en string quand on l'affecte à une variable. Ajoutez as const (`on${event}` as const) ou annotez le type cible, et TypeScript conserve le template literal type, par exemple "onclick" | "onfocus".

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER