TypeScript : satisfies

Dans cet article, nous allons voir comment tirer parti de l’opérateur satisfies introduit avec la version 4.9 de TypeScript.

Pour mieux comprendre comment à quoi sert l’opérateur satisfies, nous allons étudier un problème concret.

Challenge

Soit un type Status qui définit le statut d’une requête HTTP. Pour le moment, ses valeurs possibles sont :

  • FAILED : la requête a échoué.
  • PENDING : la requête est en cours.
  • RESOLVED : la requête a réussi.

Dans le code, ça donne quelque chose comme ça :

type Status = 'FAILED' | 'PENDING' | 'RESOLVED';

Soit un objet nommé i18n qui a pour clés les différents statuts possibles et pour valeur les traductions françaises associées à ces statuts.

const i18n = {
FAILED: 'Échec',
PENDING: 'En cours',
RESOLVED: 'Succès',
};

Notre challenge est de typer l’objet i18n de la meilleure des manières possibles, c’est-à-dire :

  • le plus spécifiquement possible à la fois pour les clés et pour les valeurs.
  • et en utilisant au maximum l’inférence de type.

Tentatives de solution

Essayons de typer notre objet i18n progressivement.

as const

Pour typer les valeurs de l’objet i18n qu’on a défini plus haut en utilisant au maximum l’inférence de type, rajoutons le mot clé as const comme suit :

const i18n = {
FAILED: 'Échec',
PADDING: 'En cours',
RESOLVED: 'Succès',
} as const;
// ^ i18n est de type : { readonly FAILED: 'Échec'; readonly RESOLVED: 'Succès'; readonly PADDING: 'En cours' };

Les valeurs sont maintenant typées le plus spécifiquement possible. Cependant, actuellement cet objet n’est aucunement lié au type Status. D’ailleurs, il contient une erreur. J’ai volontairement mis PADDING au lieu de PENDING.

Utilisation d’un Record

Nous pouvons utiliser un Record pour nous assurer du typage des clés de notre objet i18n.

type Status = 'FAILED' | 'PENDING' | 'RESOLVED';
const i18n: Record<Status, string> = {
FAILED: 'Échec',
PENDING: 'En cours',
RESOLVED: 'Succès',
} as const;
// ^ i18n est de type : Record<"FAILED" | "PENDING" | "RESOLVED", string>

Les clés ont maintenant les bons types. Cependant, le typage spécifique de notre objet (avec Record<Status, string>) l’emporte sur l’inférence de type (avec as const). On perd donc le typage précis des valeurs qui deviennent toutes des string.

La solution avec satisfies

La solution est d’utiliser le mot clé satifies comme suit pour avoir le meilleur typage à la fois des clés et des valeurs :

type Status = 'FAILED' | 'PENDING' | 'RESOLVED';
const i18n = {
FAILED: 'Échec',
PENDING: 'En cours',
RESOLVED: 'Succès',
} as const satisfies Record<Status, string>;
// ^ i18n est de type : {readonly FAILED: "Échec", readonly RESOLVED: "Succès", readonly PENDING: "En cours"}

L’opérateur satifies permet d’imposer une contrainte à une variable sans changer son type. satisfies Record<Status, string> impose donc à notre objet i18n d’avoir des clés de type Status. Combiné avec as const, notre objet i18n devient fortement typé au niveau des clés, mais aussi des valeurs.

Conclusion

Introduit avec la version 4.9, l’opérateur satisfies est une excellente addition au langage TypeScript qui nous offre un outil de plus pour mieux typer nos objets TypeScript.


Vous aimez ce blog ?
Suivez-moi sur Twitter pour plus de contenu !

Rejoignez la newsletter pour du contenu de grande qualité dans votre boite mail

Pas de spam. Que du contenu de qualité.