Mise à jour du 13/05/2020 : TypeScript 3.9 est disponible et s'accompagne d'améliorations du processus d'inférence
Quelques semaines après la Release Candidate, Microsoft annonce que la version générale de TypeScript 3.9 est disponible.
Source : Microsoft
Quelques semaines après la Release Candidate, Microsoft annonce que la version générale de TypeScript 3.9 est disponible.
Source : Microsoft
Améliorations de l’inférence et de la méthode Promise.all
Dans les versions de TypeScript (environ 3.7), les déclarations de fonctions comme Promise.all et Promise.race ont été mises à jour. Mais cela a induit des erreurs en particulier lors de la combinaison des valeurs avec null ou undefined. Dans cette dernière version, ce bogue a été corrigé avec des améliorations dans le processus d’inférence. Si vous utilisez encore une ancienne version de TypeScript et que vous avez rencontré des problèmes liés à l’objet Promise, il est désormais recommandé de passer à la version 3.9.
Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | interface Lion { roar(): void } interface Seal { singKissFromARose(): void } async function visitZoo(lionExhibit: Promise<Lion>, sealExhibit: Promise<Seal | undefined>) { let [lion, seal] = await Promise.all([lionExhibit, sealExhibit]); lion.roar(); // uh oh // ~~~~ // Object is possibly 'undefined'. } |
Si le comportement était étrange, suite à un Pull Request de Jack Bates, il a été corrigé avec des améliorations dans le processus d'inférence dans TypeScript 3.9. Ce qui précède n'est donc plus une erreur.
Qu'en est-il du type awaited
Depuis quelques années, des travaux ont été entrepris afin de concevoir un mécanisme fiable pour définir un type conditionnel récursif capable de gérer correctement les types. Cela a conduit à l’adoption de l’opérateur de type awaited. Dans sa feuille de route, l’équipe de TypeScript avait prévu intégrer cette nouvelle fonctionnalité dans TypeScript 3.9. Mais après plusieurs analyses, les mainteneurs du code ont réalisé que la fonctionnalité awaited a besoin de plus de travail de conception avant de pouvoir être déployée, car pour l’instant, la seule façon de rendre le type conditionnel awaited récursif est d’introduire un type complexe. En conséquence, cette fonctionnalité a été retirée de la branche principale.
« Si vous avez suivi notre suivi des problèmes et nos notes de réunion de conception, vous savez peut-être que certains travaux autour d'un nouvel opérateur de type awaited sont attendus. L'objectif de cet opérateur de type est de modéliser avec précision le fonctionnement de l’unwrapping de Promise en JavaScript.
« Nous avions initialement prévu de déployer awaited dans TypeScript 3.9, mais comme nous avons exécuté les premières versions de TypeScript avec les bases de code existantes, nous avons réalisé que la fonctionnalité a besoin de plus de travail de conception avant de pouvoir être déployée en douceur. En conséquence, nous avons décidé de retirer la fonctionnalité de notre branche principale jusqu'à ce que nous soyons plus confiants. Nous expérimenterons davantage la fonctionnalité, mais nous ne la livrerons pas dans le cadre de cette version ».
Améliorations de la vitesse de compilation et du temps d’application des mises à jour dans Visual Studio Code (VS Code) après le renommage de fichiers
Avec les anciennes versions de TypeScript, de nombreux développeurs ont pointé du doigt des latences relativement élevées lors de la compilation avec des paquets tels que Material-UI et les composants de style. Pour résoudre ces problèmes de performance, plusieurs solutions ont été proposées et ont permis de gagner chacune environ 5 à 10 % de temps de compilation sur certaines bases de code. En faisant le point après les améliorations apportées, l’équipe de TypeScript note une réduction d’environ 40 % du temps de compilation avec Material-UI.
À côté de l’amélioration de la vitesse de compilation, des améliorations ont été également apportées dans cette dernière version de TypeScript afin que le renommage des fichiers dans VS Code n’entraîne pas de lenteur dans l’éditeur de code. En effet, l’équipe de Visual Studio Code a rapporté que lors du changement de nom d’un fichier, la détermination des instructions d’importation à mettre à jour pouvait prendre entre 5 et 10 secondes. TypeScript 3.9 résout ce problème en modifiant les paramètres internes de la façon dont le compilateur et le service de langage mettent en cache les recherches de fichiers.
Nouveaux commentaires // @ts-expect-erreur
Imaginez que nous écrivons une bibliothèque en TypeScript et que nous exportons une fonction appelée doStuff dans le cadre de notre API publique. Les types de la fonction déclarent qu'il faut deux chaînes pour que les autres utilisateurs TypeScript puissent obtenir des erreurs de vérification de type, mais il effectue également une vérification d'exécution (peut-être uniquement dans les versions de développement) pour donner aux utilisateurs JavaScript une erreur utile.
Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 | function doStuff(abc: string, xyz: string) { assert(typeof abc === "string"); assert(typeof xyz === "string"); // do some stuff } |
Ainsi, les utilisateurs de TypeScript recevront un gribouillis rouge utile et un message d'erreur lorsqu'ils utiliseront mal cette fonction, et les utilisateurs de JavaScript recevront une erreur d'assertion. Nous aimerions tester ce comportement, nous allons donc écrire un test unitaire.
Code TypeScript : | Sélectionner tout |
1 2 3 | expect(() => { doStuff(123, 456); }).toThrow(); |
Malheureusement, si nos tests sont écrits en TypeScript, TypeScript nous donnera une erreur!
Code TypeScript : | Sélectionner tout |
1 2 3 | doStuff(123, 456); // ~~~ // error: Type 'number' is not assignable to type 'string'. |
C’est pourquoi TypeScript 3.9 apporte une nouvelle fonctionnalité: les commentaires // @ ts-expect-error. Lorsqu'une ligne est préfixée avec un commentaire // @ ts-expect-error, TypeScript empêche que cette erreur soit signalée; mais s'il n'y a pas d'erreur, TypeScript signale que // @ ts-expect-error n'était pas nécessaire.
Comme exemple rapide, le code suivant est correct :
Code TypeScript : | Sélectionner tout |
1 2 | // @ts-expect-error console.log(47 * "octopus"); |
Tandis que le code suivant
Code TypeScript : | Sélectionner tout |
1 2 | // @ts-expect-error console.log(1 + 1); |
conduit à l'erreur
Code : | Sélectionner tout |
Unused '@ts-expect-error' directive.
Elles ont été introduites dans TypeScript 3.7 pour signaler une erreur lorsqu'un développeur a oublié d'appeler une fonction :
Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | function hasImportantPermissions(): boolean { // ... } // Oops! if (hasImportantPermissions) { // ~~~~~~~~~~~~~~~~~~~~~~~ // This condition will always return true since the function is always defined. // Did you mean to call it instead? deleteAllTheImportantFiles(); } |
Cependant, cette erreur ne s'applique qu'aux conditions des instructions if. Grâce à un Pull Request d'Alexander Tarasyuk, cette fonctionnalité est également prise en charge dans les conditions ternaires (c'est-à-dire répondant à la syntaxe cond ? trueExpr : falseExp).
Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | declare function listFilesOfDirectory(dirPath: string): string[]; declare function isDirectory(): boolean; function getAllFiles(startFileName: string) { const result: string[] = []; traverse(startFileName); return result; function traverse(currentPath: string) { return isDirectory ? // ~~~~~~~~~~~ // This condition will always return true // since the function is always defined. // Did you mean to call it instead? listFilesOfDirectory(currentPath).forEach(traverse) : result.push(currentPath); } } |
Améliorations visant à préserver les nouvelles lignes
Les refactorisations et les correctifs rapides de TypeScript n'ont souvent pas fait un excellent travail pour préserver les nouvelles lignes. Comme exemple vraiment basique, prenez le code suivant.
Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | const maxValue = 100; /*start*/ for (let i = 0; i <= maxValue; i++) { // First get the squared value. let square = i ** 2; // Now print the squared value. console.log(square); } /*end*/ |
Si nous mettions en surbrillance la plage de /* start */ à /* end */ dans notre éditeur pour extraire vers une nouvelle fonction, nous nous retrouverions avec du code comme celui-ci.
Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | const maxValue = 100; printSquares(); function printSquares() { for (let i = 0; i <= maxValue; i++) { // First get the squared value. let square = i ** 2; // Now print the squared value. console.log(square); } } |
Ce n'est pas idéal - nous avions une ligne vide entre chaque instruction dans notre boucle for, mais le refactoring s'en est débarrassé! TypeScript 3.9 fait un peu plus de travail pour préserver ce que nous écrivons.
Code TypeScript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | const maxValue = 100; printSquares(); function printSquares() { for (let i = 0; i <= maxValue; i++) { // First get the squared value. let square = i ** 2; // Now print the squared value. console.log(square); } } |
Source : Microsoft