Récemment, j'ai vu un tweet de Jamie Kyle sur l'utilisation de la déstructuration, des paramètres par défaut et des types en ligne :
Ce tweet et quelques composants React que j'ai vus récemment dans mon travail quotidien m'ont inspiré pour écrire ce billet de blog. Je veux vous montrer comment l'utilisation de la déstructuration et des types inline peut rendre votre TypeScript moins lisible !
En JavaScript et TypeScript, vous pouvez définir une fonction à l'aide du mot-clé de function
ou de la fonction lambda/flèche. Les deux manières sont valables mais ont leurs différences. Jetons un coup d'œil à la simple fonction sendMessage
. La logique de mise en œuvre ne nous concerne pas.
// sendMessage function written using `function` keyword function sendMessage(message: string) { // function logic } // same sendMessage written as arrow function const sendMessage = (message: string) => { // function logic };
Lorsque la définition de la fonction est assez simple, la fonction accepte quelques paramètres d'un type différent. S'il s'agit de primitives comme des chaînes ou des nombres, tout est lisible.
Supposons que vous souhaitiez transmettre des informations supplémentaires à côté du contenu de votre message à la fonction sendMessage
.
function sendMessage(message: { content: string; senderId: string; replyTo?: string; }) { // you can assess content using `message.content` here }
Comme vous pouvez le constater, TypeScript vous permet d'écrire une définition de type en ligne pour l'objet de message
que vous souhaitez transmettre sans spécifier le type à l'aide du mot clé type
ou interface
.
Ajoutons Destructuring. Lorsque vous transmettez un objet de message
volumineux à votre fonction, TypeScript permet de séparer les arguments passés pour réduire le code passe-partout consistant à répéter plusieurs fois la variable de message
.
function sendMessage({ content, senderId, replyTo, }: { content: string; senderId: string; replyTo?: string; }) { // you have access to `content` directly }
Cela peut sembler une bonne idée, après tout, vous n'avez pas besoin d'écrire message
autant de fois, n'est-ce pas ? Il s'avère que ce n'est pas si génial. Parlons de 5 raisons pour lesquelles je pense que c'est un anti-modèle.
Lorsque vous lisez le corps de la fonction, vous voyez senderId
, vous devez revérifier pour être sûr d'où vient cette fonction. Est-il passé en argument ou calculé quelque part dans la fonction ?
Il n'y a pas d'endroit naturel pour écrire des commentaires de documentation lorsque tous les types sont à l'étroit avec la déstructuration dans la définition de la fonction. Vous pouvez écrire des commentaires entre chaque champ de type, mais cela rend la définition de la fonction entière encore plus longue. Cela vous décourage activement d'écrire un résumé rapide des données que vous transmettez.
Lorsque vos données sont déstructurées, vous devez les structurer à nouveau dans un nouvel objet si vous souhaitez les transmettre. Cela décourage la création de fonctions d'assistance plus petites et l'utilisation de la composition pour créer la logique de votre fonction principale.
Si vous avez besoin de réutiliser vos arguments de fonction dans des fonctions d'assistance lors de la composition de votre logique de fonction principale, vous devez taper le même ensemble de types à plusieurs reprises. Cela rend plus facile de ne pas écrire de types du tout.
Avouons-le. C'est juste beaucoup de lignes de code qui occupent beaucoup d'espace à l'écran. Et en plus, il se concentre sur les détails d'implémentation - le type interne des arguments que vous transmettez à une fonction, qui n'est la plupart du temps pas pertinent lorsque vous regardez cette fonction.
Extraire le type et le placer juste au-dessus de la fonction le rend beaucoup plus lisible. Il y a un endroit pour les commentaires de documentation, vous pouvez réutiliser ce type dans une autre fonction d'assistance et modifier la définition de type à un endroit si nécessaire.
/** * Message to send using XYZ API */ export type MessageToSend = { /** * Markdown string of the user's message */ content: string; /** * Id of the sender user */ senderId: string; /** * Other message ID if this is a reply */ replyTo?: string; }; function sendMessage(message: MessageToSend) { // function logic } function getUserIdsToNotify(message: MessaageToSend) { // function logic }
Trouvez une liste des ressources que j'ai utilisées lors de la recherche de cet article de blog :