TypeScript est un langage qui s'appuie sur JavaScript en ajoutant une syntaxe pour les types. Les types décrivent les formes attendues des variables, paramètres et fonctions, et le vérificateur de type TypeScript peut aider à détecter des problèmes tels que les fautes de frappe, les propriétés manquantes et les mauvais appels de fonction avant l'exécution du code. Les types alimentent également les outils d'édition de TypeScript, comme l'auto-complétion, la navigation dans le code et les refactorisations dans des éditeurs tels que Visual Studio et VS Code. En fait, si vous écrivez du JavaScript dans l'un ou l'autre de ces éditeurs, cette expérience est alimentée par TypeScript !
Microsoft vient d'annoncer la sortie de TypeScript 5.6. Depuis la version bêta de TypeScript 5.6, l'équipe de TypeScript est revenu sur un changement concernant la façon dont le service de langage TypeScript recherche les fichiers tsconfig.json. Auparavant, le service de langage n'arrêtait pas de chercher tous les fichiers de projet nommés tsconfig.json susceptibles de contenir un fichier. Comme cela pouvait conduire à l'ouverture de nombreux projets référencés, ce comportement a été annulée pour TypeScript 5.6. Elle pourrait revenir dans TypeScript 5.7.
En outre, plusieurs nouveaux types ont été renommés depuis la version bêta. Auparavant, TypeScript fournissait un seul type appelé BuiltinIterator pour décrire chaque valeur soutenue par Iterator.prototype. Il a été renommé IteratorObject, a un ensemble différent de paramètres de type, et a maintenant plusieurs sous-types comme ArrayIterator, MapIterator, et plus encore.
Un nouveau drapeau appelé --stopOnBuildErrors a été ajouté pour le mode --build. Lorsqu'un projet se construit avec des erreurs, aucun autre projet ne sera construit. Cela permet de se rapprocher du comportement des versions précédentes de TypeScript puisque TypeScript 5.6 construit toujours en cas d'erreur.
De nouvelles fonctionnalités de l'éditeur ont été ajoutées, telles que le support direct des caractères de validation et des motifs d'exclusion pour les auto-importations.
Voici quelques mises à jours de cette version :
Vérifications vraies et nulles non autorisées
Voici quelques exemples d'erreurs qui ne correspondent pas à l'intention de l'auteur, mais ils constituent tous du code JavaScript valide.
- Ecrire une regex et oublié d'appeler .test(...) dessus
- Ecrire => (qui crée une fonction flèche) au lieu de >= (l'opérateur plus grand que ou égal à)
- Utiliser une valeur par défaut avec ? ?, mais confondre la priorité de ? ? et d'un opérateur de comparaison comme <
- Mal placer une parenthèse dans une expression complexe
Auparavant, TypeScript acceptait aussi ces exemples. Mais de nombreux bogues pouvaient être détectés en signalant ces exemples suspects.
Dans TypeScript 5.6, le compilateur fait désormais des erreurs lorsqu'il peut déterminer syntaxiquement qu'une vérification vraie ou nulle sera toujours évaluée d'une manière spécifique. Ainsi, dans les exemples ci-dessus, vous commencerez à voir des erreurs :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | if (/0x[0-9a-f]/) { // ~~~~~~~~~~~~ // error: This kind of expression is always truthy. } if (x => 0) { // ~~~~~~ // error: This kind of expression is always truthy. } function isValid(value: string | number, options: any, strictness: "strict" | "loose") { if (strictness === "loose") { value = +value } return value < options.max ?? 100; // ~~~~~~~~~~~~~~~~~~~ // error: Right operand of ?? is unreachable because the left operand is never nullish. } if ( isValid(primaryValue, "strict") || isValid(secondaryValue, "strict") || isValid(primaryValue, "loose" || isValid(secondaryValue, "loose")) ) { // ~~~~~~~ // error: This kind of expression is always truthy. } |
Notez que certaines expressions sont toujours autorisées, même si elles sont toujours vraies ou nulles. Plus précisément, true, false, 0 et 1 sont toujours autorisés même si elles sont toujours vraies ou fausses.
Méthodes d'aide pour les itérateurs
JavaScript a une notion d'itérables (choses sur lesquelles on peut itérer en appelant un [Symbol.iterator]() et en obtenant un itérateur) et d'itérateurs (choses qui ont une méthode next() que l'on peut appeler pour essayer d'obtenir la valeur suivante au fur et à mesure de l'itération). En général, il n'est pas nécessaire de penser à ces choses lorsque vous les placez dans une boucle for/of, ou [...spread] dans un nouveau tableau. Mais TypeScript les modélise avec les types Iterable et Iterator (et même IterableIterator qui agit comme les deux !), et ces types décrivent l'ensemble minimal de membres dont vous avez besoin pour que des constructions comme for/of fonctionnent sur eux.
Les Iterables (et les IterableIterators) sont intéressants car ils peuvent être utilisés dans toutes sortes d'endroits en JavaScript - mais beaucoup de gens se sont aperçus qu'il manquait des méthodes sur les Arrays comme map, filter, et pour une raison ou une autre reduce. C'est pourquoi une proposition récente a été présentée dans ECMAScript pour ajouter de nombreuses méthodes (et plus) de Array à la plupart des IterableIterators qui sont produits en JavaScript.
Par exemple, chaque générateur produit désormais un objet qui possède également une méthode map et une méthode take.
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function* positiveIntegers() { let i = 1; while (true) { yield i; i++; } } const evenNumbers = positiveIntegers().map(x => x * 2); // Output: // 2 // 4 // 6 // 8 // 10 for (const value of evenNumbers.take(5)) { console.log(value); } |
Code : | Sélectionner tout |
1 2 3 4 5 | function invertKeysAndValues<K, V>(map: Map<K, V>): Map<V, K> { return new Map( map.entries().map(([k, v]) => [v, k]) ); } |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * Provides an endless stream of `0`s. */ class Zeroes extends Iterator<number> { next() { return { value: 0, done: false } as const; } } const zeroes = new Zeroes(); // Transform into an endless stream of `1`s. const ones = zeroes.map(x => x + 1); |
Code : | Sélectionner tout |
Iterator.from(...).filter(someFunction);
Concernant le nommage : TypeScript dispose de types pour Iterable et Iterator, cependant, ces types agissent en quelque sorte comme des "protocoles" pour garantir le bon fonctionnement de certaines opérations. "Cela signifie que toutes les valeurs déclarées Iterable ou Iterator en TypeScript ne disposent pas de ces méthodes.
Mais il existe toujours une nouvelle valeur d'exécution appelée Iterator. Vous pouvez référencer Iterator, ainsi que Iterator.prototype, comme des valeurs réelles en JavaScript. C'est un peu gênant car TypeScript définit déjà sa propre chose appelée Iterator uniquement pour la vérification de type. En raison de ce malheureux conflit de noms, TypeScript doit donc introduire un type distinct pour décrire ces itérateurs natifs/intégrés.
TypeScript 5.6 introduit un nouveau type appelé IteratorObject. Il est défini comme suit :
Code : | Sélectionner tout |
1 2 3 | interface IteratorObject<T, TReturn = unknown, TNext = unknown> extends Iterator<T, TReturn, TNext> { [Symbol.iterator](): IteratorObject<T, TReturn, TNext>; } |
De même, il existe un type AsyncIteratorObject pour la parité. AsyncIterator n'existe pas encore en tant que valeur d'exécution en JavaScript qui apporte les mêmes méthodes pour AsyncIterables, mais c'est une proposition active et ce nouveau type s'y prépare.
L'option --noCheck
TypeScript 5.6 introduit une nouvelle option de compilation, --noCheck, qui permet d'ignorer la vérification de type pour tous les fichiers d'entrée. Cela permet d'éviter les vérifications de type inutiles lors de l'analyse sémantique nécessaire à l'émission des fichiers de sortie.
Un scénario pour cela est de séparer la génération de fichiers JavaScript de la vérification de type afin que les deux puissent être exécutés comme des phases distinctes. Par exemple, vous pouvez exécuter tsc --noCheck pendant l'itération, puis tsc --noEmit pour une vérification complète du type. Vous pouvez également exécuter les deux tâches en parallèle, même en mode --watch, bien que vous devriez probablement spécifier un chemin --tsBuildInfoFile séparé si vous les exécutez vraiment en même temps.
--noCheck est également utile pour émettre des fichiers de déclaration d'une manière similaire. Dans un projet où --noCheck est spécifié sur un projet conforme à --isolatedDeclarations, TypeScript peut rapidement générer des fichiers de déclaration sans passer par la vérification de type. Les fichiers de déclaration générés s'appuieront uniquement sur des transformations syntaxiques rapides.
Notez que dans les cas où --noCheck est spécifié, mais qu'un projet n'utilise pas --isolatedDeclarations, TypeScript peut toujours effectuer autant de vérifications de type que nécessaire pour générer des fichiers .d.ts. Dans ce sens, --noCheck est un peu mal nommé ; cependant, le processus sera plus paresseux qu'une vérification de type complète, ne calculant que les types des déclarations non annotées. Cela devrait être beaucoup plus rapide qu'une vérification de type complète.
noCheck est également disponible via l'API TypeScript en tant qu'option standard. En interne, transpileModule et transpileDeclaration utilisaient déjà noCheck pour accélérer les choses (au moins à partir de TypeScript 5.5). Désormais, n'importe quel outil de compilation devrait être en mesure de tirer parti de ce drapeau, en adoptant une variété de stratégies personnalisées pour coordonner et accélérer les compilations.
Autoriser --build avec des erreurs intermédiaires
Le concept de références de projet de TypeScript vous permet d'organiser votre base de code en plusieurs projets et de créer des dépendances entre eux. L'exécution du compilateur TypeScript en mode --build (ou tsc -b en abrégé) est le moyen intégré de mener cette compilation à travers les projets et de déterminer quels projets et quels fichiers doivent être compilés.
Auparavant, l'utilisation du mode --build supposait --noEmitOnError et arrêtait immédiatement la compilation en cas d'erreur. Cela signifiait que les projets "en aval" ne pouvaient jamais être vérifiés et compilés si l'une de leurs dépendances "en amont" avait des erreurs de compilation. En théorie, il s'agit d'une approche très cromulante - si un projet a des erreurs, il n'est pas nécessairement dans un état cohérent pour ses dépendances.
En réalité, ce type de rigidité rendait des choses comme les mises à jour pénibles. Par exemple, si le projetB dépend du projetA, les personnes qui connaissent mieux le projetB ne peuvent pas mettre à jour leur code de manière proactive tant que leurs dépendances n'ont pas été mises à jour. Ils sont bloqués par le travail de mise à niveau du projetA en premier lieu.
À partir de TypeScript 5.6, le mode --build continuera à construire des projets même s'il y a des erreurs intermédiaires dans les dépendances. Les erreurs intermédiaires seront signalées de manière cohérente et les fichiers de sortie seront générés au mieux ; cependant, la construction se poursuivra jusqu'à son terme sur le projet spécifié.
Si vous souhaitez arrêter la compilation au premier projet contenant des erreurs, vous pouvez utiliser un nouveau drapeau appelé --stopOnBuildErrors. Cela peut être utile lorsque vous travaillez dans un environnement CI, ou lorsque vous itérez sur un projet qui est fortement dépendant d'autres projets.
Notez que pour ce faire, TypeScript émet toujours un fichier .tsbuildinfo pour tout projet dans une invocation --build (même si --incremental/--composite n'est pas spécifié). Cela permet de garder une trace de l'état de l'invocation de --build et du travail à effectuer dans le futur.
Source : Microsoft
Et vous ?
Quel est votre avis sur cette nouvelle version de TypeScript ?
Voir aussi :
Microsoft annonce la disponibilité de TypeScript 5.5, cette version apporte les prédicats de type inférés, les déclarations isolées, ainsi qu'une amélioration de la fiabilité de l'éditeur
Cinq vérités inconfortables à propos de TypeScript selon Stefan Baumgartner, auteur de livres sur le langage de programmation
TypeScript, les types marqués : Produire un moyen de marquer un type, en fournissant un moyen automatisé et facile à utiliser pour rendre un type nominal, par Prosopo