Menu

Types littéraux et as const en TypeScript, avec exemples

Un type littéral est un type qui n'a qu'une seule valeur, comme "GET" ou 404. Découvrez les types littéraux string, number et boolean, les unions de littéraux, pourquoi let élargit et const non, ce que fait as const, et les paramètres de type const.

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

Un type littéral est un type qui n'a qu'une seule valeur : "up" est un type dont le seul membre est la chaîne "up", et 404 un type dont le seul membre est le nombre 404. Seuls, ils ne servent pas à grand-chose. Réunis en une union, ils donnent une variable qui accepte un ensemble fixe de valeurs et rien d'autre.

Sans le commentaire @ts-expect-error, le dernier appel est une erreur de compilation (TS2345). Avec lui, le programme compile et l'appel s'exécute quand même en affichant moving north by 1 : les types littéraux n'existent que pour le compilateur, et à l'exécution la valeur est une chaîne ordinaire.

Littéraux string, number et boolean

N'importe quelle valeur string, number, bigint ou boolean peut s'écrire comme un type. Le compilateur n'accepte alors que cette valeur exacte.

let method: "GET" = "GET";
let code: 404 = 404;
let ok: true = true;
let big: 10n = 10n;

type Port = 80 | 443 | 8080;
const port: Port = 443;

boolean n'est lui-même que l'union true | false, c'est pourquoi affiner un boolean avec if (flag) laisse false dans la branche else.

Type littéralAutoriseType plus large
"GET"uniquement la chaîne "GET"string
404uniquement le nombre 404number
10nuniquement le bigint 10bigint
trueuniquement trueboolean

Unions de littéraux

L'usage courant est une union qui liste chaque valeur autorisée. Dans la fonction, le compilateur affine l'union au fil de vos vérifications, et chaque branche sait exactement quelle valeur elle a.

Une union de littéraux de chaîne est l'alternative habituelle à un enum en TypeScript. Elle ne coûte rien à l'exécution, les valeurs sont de simples chaînes que vous pouvez journaliser et envoyer en JSON, et une faute de frappe est une erreur de compilation. Les compromis sont détaillés dans enums.

Élargissement : let ou const

Quand TypeScript infère un type à partir d'un littéral, il regarde si la valeur peut changer. Une variable const ne peut jamais être réassignée, elle garde donc le type littéral. Une variable let le peut, son type est donc élargi au type général.

Survolez chaque nom dans l'éditeur pour voir le type inféré. Si vous voulez une let qui ne contienne que certaines valeurs, annotez-la : let mode: "light" | "dark" = "light".

Pourquoi les propriétés d'objet s'élargissent

Les propriétés d'un littéral objet sont modifiables, elles s'élargissent donc aussi, même quand l'objet est stocké dans une const. C'est la façon la plus courante de tomber sur les types littéraux par accident :

Le compilateur signale :

index.ts(7,15): error TS2345: Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'.

req est inféré comme { url: string; method: string }, car du code pourrait plus tard exécuter req.method = "DELETE". Il y a trois corrections :

Une quatrième option est satisfies, qui vérifie l'objet par rapport à un type tout en gardant les types littéraux de ses propriétés.

as const

as const est une const assertion. Placez-la après une expression et le compilateur infère le type le plus étroit possible :

  • les valeurs string, number et boolean gardent leurs types littéraux
  • les propriétés d'objet deviennent readonly
  • les littéraux de tableau deviennent des tuples readonly de longueur fixe

L'assertion n'agit qu'à la compilation. Le JavaScript émis est le même littéral objet sans as const : rien n'empêche donc un autre code de le modifier à l'exécution. Si vous avez besoin d'une garantie à l'exécution, appelez aussi Object.freeze.

Un type union à partir d'un tableau as const

Un motif fréquent consiste à garder les valeurs autorisées dans un seul tableau, que vous pouvez parcourir à l'exécution, et à en dériver le type union. (typeof arr)[number] signifie « le type de n'importe quel élément de arr ».

Sans as const, ROLES serait un string[] et Role un simple string. La conversion en readonly string[] dans isRole est nécessaire parce que includes sur un tuple de littéraux n'accepte que ces littéraux, alors que le but de la fonction est de tester une chaîne qui n'en est peut-être pas un. Le même motif fonctionne pour les tables clé/valeur : const Status = { Active: "active", Banned: "banned" } as const, puis type Status = (typeof Status)[keyof typeof Status].

Paramètres de type const

Une fonction générique élargit normalement les littéraux que vous lui passez. Depuis TypeScript 5.0, vous pouvez marquer un paramètre de type const, ce qui fait inférer l'argument par le compilateur comme s'il portait as const, sans demander à l'appelant de l'écrire.

C'est surtout un outil pour les auteurs de bibliothèques : les définitions de routes, les builders et les helpers de schéma l'utilisent pour que les appelants obtiennent des types précis à partir de simples littéraux.

Les sens de const

Le mot-clé const apparaît à quatre endroits différents dans du code TypeScript :

SyntaxeNatureEffet
const x = 1Déclaration JavaScriptla liaison ne peut pas être réassignée ; une valeur littérale garde son type littéral
expr as constAssertion TypeScripttype le plus étroit : littéraux, propriétés readonly, tuples readonly
function f<const T>()Paramètre de type TypeScriptinfère les arguments comme s'ils portaient as const
const enum E {}Enum TypeScriptun enum dont les membres sont remplacés par leur valeur à la compilation

Aucun d'eux ne gèle un objet à l'exécution. const obj = { a: 1 } autorise toujours obj.a = 2 ; seule la réassignation de obj lui-même est une erreur.

Questions fréquentes

Qu'est-ce qu'un type littéral en TypeScript ?

Un type qui n'autorise qu'une seule valeur. "GET" est un type dont la seule valeur est la chaîne "GET", 404 est un type dont la seule valeur est le nombre 404, et true est un type dont la seule valeur est true. Ils sont surtout utiles combinés en unions, comme type Method = "GET" | "POST".

Que fait as const en TypeScript ?

as const est une const assertion. Elle demande au compilateur d'inférer le type le plus étroit pour une expression : les valeurs string et number gardent leurs types littéraux, les propriétés d'objet deviennent readonly, et les littéraux de tableau deviennent des tuples readonly. Seul le type change ; à l'exécution, la valeur est le même objet ou tableau ordinaire, et elle n'est pas gelée.

Pourquoi TypeScript infère-t-il string au lieu de mon littéral ?

Parce que la valeur est modifiable. let x = "a" et la propriété dans { method: "GET" } peuvent être réassignées plus tard, TypeScript les élargit donc en string. Une variable const garde le type littéral "a". Pour conserver des littéraux dans un objet, annotez-le avec le type littéral, utilisez as const, ou utilisez satisfies.

Quelle est la différence entre const et as const ?

const est une déclaration JavaScript : la variable ne peut pas être réassignée, mais l'objet vers lequel elle pointe peut toujours être modifié. as const est une assertion de type TypeScript : elle rend chaque propriété de la valeur readonly et littérale dans le système de types. Aucun des deux ne gèle l'objet à l'exécution ; utilisez Object.freeze pour cela.

Comment obtenir un type union à partir d'un tableau de chaînes ?

Déclarez le tableau avec as const, puis indexez son type avec number : const roles = ["admin", "user"] as const; type Role = (typeof roles)[number]; donne "admin" | "user". Sans as const, le tableau est un string[] et le résultat n'est qu'un string.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER